Hi,
Here is a series of patches wich improve i855 support and a new board with that chipset.
The board boots successfully with Seabios into Linux!
There are still a few blacks left to filled in (undocumented chipset registers, some RAM parameters i have no idea how to compute). So any comment is welcome!
Regards Andreas
Signed-off-by: Andreas Schultz aschultz@tpip.net --- src/cpu/intel/socket_mPGA479M/Kconfig | 1 + src/cpu/intel/socket_mPGA479M/Makefile.inc | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/src/cpu/intel/socket_mPGA479M/Kconfig b/src/cpu/intel/socket_mPGA479M/Kconfig index 4ee8e1b..8598eaf 100644 --- a/src/cpu/intel/socket_mPGA479M/Kconfig +++ b/src/cpu/intel/socket_mPGA479M/Kconfig @@ -3,5 +3,6 @@ config CPU_INTEL_SOCKET_MPGA479M select CPU_INTEL_MODEL_69X select CPU_INTEL_MODEL_6BX select CPU_INTEL_MODEL_6DX + select CPU_INTEL_MODEL_F2X select MMX select SSE diff --git a/src/cpu/intel/socket_mPGA479M/Makefile.inc b/src/cpu/intel/socket_mPGA479M/Makefile.inc index d16cc76..2cf418f 100644 --- a/src/cpu/intel/socket_mPGA479M/Makefile.inc +++ b/src/cpu/intel/socket_mPGA479M/Makefile.inc @@ -1,6 +1,7 @@ obj-y += socket_mPGA479M.o subdirs-y += ../model_69x subdirs-y += ../model_6dx +subdirs-y += ../model_f2x subdirs-y += ../../x86/tsc subdirs-y += ../../x86/mtrr subdirs-y += ../../x86/lapic @@ -9,3 +10,4 @@ subdirs-y += ../../x86/smm subdirs-y += ../microcode subdirs-y += ../hyperthreading
+cpu_incs += $(src)/cpu/intel/car/cache_as_ram.inc \ No newline at end of file
Signed-off-by: Andreas Schultz aschultz@tpip.net --- src/northbridge/intel/i855/Kconfig | 30 + src/northbridge/intel/i855/i855.h | 76 +++ src/northbridge/intel/i855/northbridge.c | 21 + src/northbridge/intel/i855/raminit.c | 1036 +++++++++++++++++++++++++----- src/northbridge/intel/i855/raminit.h | 14 +- 5 files changed, 1002 insertions(+), 175 deletions(-) create mode 100644 src/northbridge/intel/i855/i855.h
diff --git a/src/northbridge/intel/i855/Kconfig b/src/northbridge/intel/i855/Kconfig index 3d3443a..f5c2890 100644 --- a/src/northbridge/intel/i855/Kconfig +++ b/src/northbridge/intel/i855/Kconfig @@ -1,3 +1,33 @@ config NORTHBRIDGE_INTEL_I855 bool + select HAVE_DEBUG_RAM_SETUP
+choice + prompt "Onboard graphics" + default I855_VIDEO_MB_8MB + depends on NORTHBRIDGE_INTEL_I855 + +config I855_VIDEO_MB_OFF + bool "Disabled, 0KB" +config I855_VIDEO_MB_1MB + bool "Enabled, 1MB" +config I855_VIDEO_MB_4MB + bool "Enabled, 4MB" +config I855_VIDEO_MB_8MB + bool "Enabled, 8MB" +config I855_VIDEO_MB_16MB + bool "Enabled, 16MB" +config I855_VIDEO_MB_32MB + bool "Enabled, 32MB" + +endchoice + +config VIDEO_MB + int + default 0 if I855_VIDEO_MB_OFF + default 1 if I855_VIDEO_MB_1MB + default 4 if I855_VIDEO_MB_4MB + default 8 if I855_VIDEO_MB_8MB + default 16 if I855_VIDEO_MB_16MB + default 32 if I855_VIDEO_MB_32MB + depends on NORTHBRIDGE_INTEL_I855 diff --git a/src/northbridge/intel/i855/i855.h b/src/northbridge/intel/i855/i855.h new file mode 100644 index 0000000..0e11e23 --- /dev/null +++ b/src/northbridge/intel/i855/i855.h @@ -0,0 +1,76 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Travelping GmbH info@travelping.com + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Host-Hub Interface Bridge */ +#define GMC 0x50 /* GMCH Misc. Control (0x0000) */ +#define GGC 0x52 /* GMCH Graphics Control (0x0030) */ +#define DAFC 0x54 /* Device and Function Control (0x0000) */ +#define FDHC 0x58 /* Fixed Dram Hole Control */ +#define PAM0 0x59 /* Programmable Attribute Map #0 (0x00) */ +#define PAM1 0x5a /* Programmable Attribute Map #1 (0x00) */ +#define PAM2 0x5b /* Programmable Attribute Map #2 (0x00) */ +#define PAM3 0x5c /* Programmable Attribute Map #3 (0x00) */ +#define PAM4 0x5d /* Programmable Attribute Map #4 (0x00) */ +#define PAM5 0x5e /* Programmable Attribute Map #5 (0x00) */ +#define PAM6 0x5f /* Programmable Attribute Map #6 (0x00) */ +#define SMRAM 0x60 /* System Management RAM Control (0x02) */ +#define ESMRAMC 0x61 /* Extended System Management RAM Control (0x38) */ +#define ERRSTS 0x62 /* Error Status (0x0000) */ +#define ERRCMD 0x64 /* Error Command (0x0000) */ +#define SMICMD 0x66 /* SMI Command (0x00) */ +#define SCICMD 0x67 /* SCI Command (0x00) */ +#define SHIC 0x74 /* Secondary Host Interface Control Register (0x00006010) */ +#define ACAPID 0xA0 /* AGP Capability Identifier (0x00200002) */ +#define AGPSTAT 0xA4 /* AGP Status Register (0x1f000217) */ +#define AGPCMD 0xA8 /* AGP Command (0x0000) */ +#define AGPCTRL 0xB0 /* AGP Control (0x0000) */ +#define AFT 0xB2 /* AGP Functional Test (0xe9f0) */ +#define ATTBASE 0xB8 /* Aperture Translation Table Base (0x00000000) */ +#define AMTT 0xBC /* AGP Interface Multi Transaction Timer (0x00) */ +#define LPTT 0xBD /* Low Priority Transaction Timer (0x00) */ +#define HEM 0xF0 /* Host Error Control/Status/Obs (0x00000000) */ + +/* Main Memory Control */ +#define DRB 0x40 /* DRAM Row 0-3 Boundary (0x00000000) */ +#define DRA 0x50 /* DRAM Row 0-3 Attribute (0x7777) */ +#define DRT 0x60 /* DRAM Timing (0x18004425) */ +#define PWRMG 0x68 /* DRAM Controller Power Management Control (0x00000000) */ +#define DRC 0x70 /* DRAM Controller Mode (0x00000081) */ +#define DTC 0xA0 /* DRAM Throttling Control (0x00000000) */ + +#define DRT_CAS_MASK (3 << 5) +#define DRT_CAS_2_0 (1 << 5) +#define DRT_CAS_2_5 (0 << 5) + +#define DRT_TRP_MASK 3 +#define DRT_TRP_4 0 +#define DRT_TRP_3 1 +#define DRT_TRP_2 2 + +#define DRT_RCD_MASK (3 << 2) +#define DRT_RCD_4 (0 << 2) +#define DRT_RCD_3 (1 << 2) +#define DRT_RCD_2 (2 << 2) + +#define DRT_TRAS_MIN_MASK (3 << 9) +#define DRT_TRAS_MIN_8 (0 << 9) +#define DRT_TRAS_MIN_7 (1 << 9) +#define DRT_TRAS_MIN_6 (2 << 9) +#define DRT_TRAS_MIN_5 (3 << 9) diff --git a/src/northbridge/intel/i855/northbridge.c b/src/northbridge/intel/i855/northbridge.c index 77d1564..220f722 100644 --- a/src/northbridge/intel/i855/northbridge.c +++ b/src/northbridge/intel/i855/northbridge.c @@ -25,6 +25,7 @@ #include <stdint.h> #include <device/device.h> #include <device/pci.h> +#include <device/pci_ids.h> #include <stdlib.h> #include <string.h> #include <bitops.h> @@ -32,6 +33,26 @@ #include <cpu/cpu.h> #include "chip.h"
+static void northbridge_init(device_t dev) +{ + printk(BIOS_SPEW, "Northbridge init\n"); +} + +static struct device_operations northbridge_operations = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = northbridge_init, + .enable = 0, + .ops_pci = 0, +}; + +static const struct pci_driver northbridge_driver __pci_driver = { + .ops = &northbridge_operations, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x3580, +}; + static void ram_resource(device_t dev, unsigned long index, unsigned long basek, unsigned long sizek) { diff --git a/src/northbridge/intel/i855/raminit.c b/src/northbridge/intel/i855/raminit.c index 386eda1..e611d8e 100644 --- a/src/northbridge/intel/i855/raminit.c +++ b/src/northbridge/intel/i855/raminit.c @@ -18,256 +18,452 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+#include <assert.h> +#include <spd.h> #include <sdram_mode.h> +#include <stdlib.h> #include <delay.h> +#include "i855.h"
-#define dumpnorth() dump_pci_device(PCI_DEV(0, 0, 1)) -#define VG85X_MODE (SDRAM_BURST_4 | SDRAM_BURST_INTERLEAVED | SDRAM_CAS_2_5) +#define VALIDATE_DIMM_COMPATIBILITY
-/** - * Set only what I need until it works, then make it figure things out on boot - * assumes only one dimm is populated - */ +/* Debugging macros. */ +#if CONFIG_DEBUG_RAM_SETUP +#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x) +#define DUMPNORTH() dump_pci_device(NORTHBRIDGE_MMC) +#else +#define PRINTK_DEBUG(x...) +#define DUMPNORTH() +#endif
-static void sdram_set_registers(const struct mem_controller *ctrl) +#define delay() udelay(200) + +#define VG85X_MODE (SDRAM_BURST_4 | SDRAM_BURST_INTERLEAVED | SDRAM_CAS_2_5) + +/* DRC[10:8] - Refresh Mode Select (RMS). + * 0x0 for Refresh Disabled (Self Refresh) + * 0x1 for Refresh interval 15.6 us for 133MHz + * 0x2 for Refresh interval 7.8 us for 133MHz + * 0x7 for Refresh interval 64 Clocks. (Fast Refresh Mode) + */ +#define RAM_COMMAND_REFRESH 0x1 + +/* DRC[6:4] - SDRAM Mode Select (SMS). */ +#define RAM_COMMAND_SELF_REFRESH 0x0 +#define RAM_COMMAND_NOP 0x1 +#define RAM_COMMAND_PRECHARGE 0x2 +#define RAM_COMMAND_MRS 0x3 +#define RAM_COMMAND_EMRS 0x4 +#define RAM_COMMAND_CBR 0x6 +#define RAM_COMMAND_NORMAL 0x7 + +/* DRC[29] - Initialization Complete (IC). */ +#define RAM_COMMAND_IC 0x1 + +struct dimm_size { + unsigned int side1; + unsigned int side2; +}; + +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ +/* DEFINITIONS */ +/**********************************************************************************/ + +static const uint32_t refresh_frequency[] = { + /* Relative frequency (array value) of each E7501 Refresh Mode Select + * (RMS) value (array index) + * 0 == least frequent refresh (longest interval between refreshes) + * [0] disabled -> 0 + * [1] 15.6 usec -> 2 + * [2] 7.8 usec -> 3 + * [3] 64 usec -> 1 + * [4] reserved -> 0 + * [5] reserved -> 0 + * [6] reserved -> 0 + * [7] 64 clocks -> 4 + */ + 0, 2, 3, 1, 0, 0, 0, 4 +}; + +static const uint32_t refresh_rate_map[] = { + /* Map the JEDEC spd refresh rates (array index) to i855 Refresh Mode + * Select values (array value) + * These are all the rates defined by JESD21-C Appendix D, Rev. 1.0 + * The i855 supports only 15.6 us (1), 7.8 us (2) and + * 64 clock (481 ns) (7) refresh. + * [0] == 15.625 us -> 15.6 us + * [1] == 3.9 us -> 481 ns + * [2] == 7.8 us -> 7.8 us + * [3] == 31.3 us -> 15.6 us + * [4] == 62.5 us -> 15.6 us + * [5] == 125 us -> 15.6 us + */ + 1, 7, 2, 1, 1, 1 +}; + +#define MAX_SPD_REFRESH_RATE ((sizeof(refresh_rate_map) / sizeof(uint32_t)) - 1) + +/*----------------------------------------------------------------------------- +SPD functions. +-----------------------------------------------------------------------------*/ + +static void die_on_spd_error(int spd_return_value) { - /* - print_debug("Before configuration:\n"); - dump_pci_devices(); - */ + if (spd_return_value < 0) + PRINTK_DEBUG("Error reading SPD info: got %d\n", spd_return_value); +/* + if (spd_return_value < 0) + die("Error reading SPD info\n"); +*/ }
-static void spd_set_row_attributes(const struct mem_controller *ctrl) +//---------------------------------------------------------------------------------- +// Function: sdram_spd_get_page_size +// Parameters: dimm_socket_address - SMBus address of DIMM socket to interrogate +// Return Value: struct dimm_size - log2(page size) for each side of the DIMM. +// Description: Calculate the page size for each physical bank of the DIMM: +// log2(page size) = (# columns) + log2(data width) +// +// NOTE: page size is the total number of data bits in a row. +// +static struct dimm_size sdram_spd_get_page_size(uint16_t dimm_socket_address) { - uint16_t dra_reg; + uint16_t module_data_width; + int value; + struct dimm_size pgsz;
- dra_reg = 0x7733; - pci_write_config16(ctrl->d0, 0x50, dra_reg); -} + pgsz.side1 = 0; + pgsz.side2 = 0;
-static void spd_set_dram_controller_mode(const struct mem_controller *ctrl) -{ - uint32_t drc_reg; + // Side 1 + value = spd_read_byte(dimm_socket_address, SPD_NUM_COLUMNS); + die_on_spd_error(value);
- /* drc_reg = 0x00009101; */ - drc_reg = 0x00009901; - pci_write_config32(ctrl->d0, 0x70, drc_reg); -} + pgsz.side1 = value & 0xf; // # columns in bank 1
-static void spd_set_dram_timing(const struct mem_controller *ctrl) -{ - uint32_t drt_reg; + /* Get the module data width and convert it to a power of two */ + value = spd_read_byte(dimm_socket_address, SPD_MODULE_DATA_WIDTH_MSB); + die_on_spd_error(value);
- drt_reg = 0x2a004405; - pci_write_config32(ctrl->d0, 0x60, drt_reg); -} + module_data_width = (value & 0xff) << 8;
-static void spd_set_dram_size(const struct mem_controller *ctrl) -{ - uint32_t drb_reg; + value = spd_read_byte(dimm_socket_address, SPD_MODULE_DATA_WIDTH_LSB); + die_on_spd_error(value);
- drb_reg = 0x20202010; - pci_write_config32(ctrl->d0, 0x40, drb_reg); -} + module_data_width |= (value & 0xff);
-static void spd_set_dram_pwr_management(const struct mem_controller *ctrl) -{ - uint32_t pwrmg_reg; + pgsz.side1 += log2(module_data_width);
- pwrmg_reg = 0x10f10430; - pci_write_config32(ctrl->d0, 0x68, pwrmg_reg); + /* side two */ + value = spd_read_byte(dimm_socket_address, SPD_NUM_DIMM_BANKS); + die_on_spd_error(value); + +/* + if (value > 2) + die("Bad SPD value\n"); +*/ + if (value > 2) + PRINTK_DEBUG("Bad SPD value\n"); + + if (value == 2) { + pgsz.side2 = pgsz.side1; // Assume symmetric banks until we know differently + value = spd_read_byte(dimm_socket_address, SPD_NUM_COLUMNS); + die_on_spd_error(value); + + if ((value & 0xf0) != 0) { + // Asymmetric banks + pgsz.side2 -= value & 0xf; /* Subtract out columns on side 1 */ + pgsz.side2 += (value >> 4) & 0xf; /* Add in columns on side 2 */ + } + } + + return pgsz; }
-static void spd_set_dram_throttle_control(const struct mem_controller *ctrl) +//---------------------------------------------------------------------------------- +// Function: sdram_spd_get_width +// Parameters: dimm_socket_address - SMBus address of DIMM socket to interrogate +// Return Value: dimm_size - width in bits of each DIMM side's DRAMs. +// Description: Read the width in bits of each DIMM side's DRAMs via SPD. +// (i.e. 4, 8, 16) +// +static struct dimm_size sdram_spd_get_width(uint16_t dimm_socket_address) { - uint32_t dtc_reg; + int value; + struct dimm_size width; + + width.side1 = 0; + width.side2 = 0; + + value = spd_read_byte(dimm_socket_address, SPD_PRIMARY_SDRAM_WIDTH); + die_on_spd_error(value); + + width.side1 = value & 0x7f; // Mask off bank 2 flag + + if (value & 0x80) { + width.side2 = width.side1 << 1; // Bank 2 exists and is double-width + } else { + // If bank 2 exists, it's the same width as bank 1 + value = spd_read_byte(dimm_socket_address, SPD_NUM_DIMM_BANKS); + die_on_spd_error(value); + +#ifdef ROMCC_IF_BUG_FIXED + if (value == 2) + width.side2 = width.side1; +#else + switch (value) { + case 2: + width.side2 = width.side1; + break; + + default: + break; + } +#endif + }
- dtc_reg = 0x300aa2ff; - pci_write_config32(ctrl->d0, 0xa0, dtc_reg); + return width; }
-#define delay() udelay(200) - -/* if ram still doesn't work do this function */ -static void spd_set_undocumented_registers(const struct mem_controller *ctrl) +//---------------------------------------------------------------------------------- +// Function: spd_get_dimm_size +// Parameters: dimm_socket_address - SMBus address of DIMM socket to interrogate +// Return Value: dimm_size - log2(number of bits) for each side of the DIMM +// Description: Calculate the log base 2 size in bits of both DIMM sides. +// log2(# bits) = (# columns) + log2(data width) + +// (# rows) + log2(banks per SDRAM) +// +// Note that it might be easier to use SPD byte 31 here, it has the +// DIMM size as a multiple of 4MB. The way we do it now we can size +// both sides of an asymmetric dimm. +// +static struct dimm_size spd_get_dimm_size(unsigned dimm) { - /* 0:0.0 */ - /* - pci_write_config32(PCI_DEV(0, 0, 0), 0x10, 0xe0000008); - pci_write_config32(PCI_DEV(0, 0, 0), 0x2c, 0x35808086); - pci_write_config32(PCI_DEV(0, 0, 0), 0x48, 0xfec10000); - pci_write_config32(PCI_DEV(0, 0, 0), 0x50, 0x00440100); + int value;
- pci_write_config32(PCI_DEV(0, 0, 0), 0x58, 0x11111000); + // Start with log2(page size) + struct dimm_size sz = sdram_spd_get_page_size(dimm);
- pci_write_config16(PCI_DEV(0, 0, 0), 0x52, 0x0002); - */ - pci_write_config16(PCI_DEV(0, 0, 0), 0x52, 0x0044); - /* - pci_write_config16(PCI_DEV(0, 0, 0), 0x52, 0x0000); - */ - pci_write_config32(PCI_DEV(0, 0, 0), 0x58, 0x33333000); - pci_write_config32(PCI_DEV(0, 0, 0), 0x5c, 0x33333333); - /* - pci_write_config32(PCI_DEV(0, 0, 0), 0x60, 0x0000390a); - pci_write_config32(PCI_DEV(0, 0, 0), 0x74, 0x02006056); - pci_write_config32(PCI_DEV(0, 0, 0), 0x78, 0x00800001); - */ - pci_write_config32(PCI_DEV(0, 0, 0), 0xa8, 0x00000001); + if (sz.side1 > 0) { + value = spd_read_byte(dimm, SPD_NUM_ROWS); + die_on_spd_error(value);
- pci_write_config32(PCI_DEV(0, 0, 0), 0xbc, 0x00001020); - /* - pci_write_config32(PCI_DEV(0, 0, 0), 0xfc, 0x00000109); - */ + sz.side1 += value & 0xf;
- /* 0:0.1 */ - pci_write_config32(ctrl->d0, 0x74, 0x00000001); - pci_write_config32(ctrl->d0, 0x78, 0x001fe974); - pci_write_config32(ctrl->d0, 0x80, 0x00af0039); - pci_write_config32(ctrl->d0, 0x84, 0x0000033c); - pci_write_config32(ctrl->d0, 0x88, 0x00000010); - pci_write_config32(ctrl->d0, 0x98, 0xde5a868c); - pci_write_config32(ctrl->d0, 0x9c, 0x404e0046); - pci_write_config32(ctrl->d0, 0xa8, 0x00020e1a); - pci_write_config32(ctrl->d0, 0xb4, 0x0044cdac); - pci_write_config32(ctrl->d0, 0xb8, 0x000055d4); - pci_write_config32(ctrl->d0, 0xbc, 0x024acd38); - pci_write_config32(ctrl->d0, 0xc0, 0x00000003); - - /* 0:0.3 */ - /* - pci_write_config32(PCI_DEV(0, 0, 3), 0x2c, 0x35858086); - pci_write_config32(PCI_DEV(0, 0, 3), 0x44, 0x11110000); - pci_write_config32(PCI_DEV(0, 0, 3), 0x48, 0x09614a3c); - pci_write_config32(PCI_DEV(0, 0, 3), 0x4c, 0x4b09604a); - pci_write_config32(PCI_DEV(0, 0, 3), 0x50, 0x00000962); - pci_write_config32(PCI_DEV(0, 0, 3), 0x5c, 0x0b023331); - pci_write_config32(PCI_DEV(0, 0, 3), 0x6c, 0x0000402e); - pci_write_config32(PCI_DEV(0, 0, 3), 0x78, 0xe7c70f7f); - pci_write_config32(PCI_DEV(0, 0, 3), 0x7c, 0x0284007f); - pci_write_config32(PCI_DEV(0, 0, 3), 0x84, 0x000000ef); - */ + if (sz.side2 > 0) { + // Double-sided DIMM + if (value & 0xF0) + sz.side2 += value >> 4; // Asymmetric + else + sz.side2 += value; // Symmetric + }
- /* - pci_write_config16(PCI_DEV(0, 0, 3), 0xc0, 0x0200); - pci_write_config16(PCI_DEV(0, 0, 3), 0xc0, 0x0400); - */ + value = spd_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM); + die_on_spd_error(value);
- /* - pci_write_config32(PCI_DEV(0, 0, 3), 0xc4, 0x00000000); - pci_write_config32(PCI_DEV(0, 0, 3), 0xd8, 0xff00c308); - pci_write_config32(PCI_DEV(0, 0, 3), 0xdc, 0x00000025); - pci_write_config32(PCI_DEV(0, 0, 3), 0xe0, 0x001f002a); - pci_write_config32(PCI_DEV(0, 0, 3), 0xe4, 0x009f0098); - pci_write_config32(PCI_DEV(0, 0, 3), 0xec, 0x00000400); - pci_write_config32(PCI_DEV(0, 0, 3), 0xf0, 0xc0000000); - */ -} + value = log2(value); + sz.side1 += value; + if (sz.side2 > 0) + sz.side2 += value; + }
-static void sdram_set_spd_registers(const struct mem_controller *ctrl) -{ - spd_set_row_attributes(ctrl); - spd_set_dram_controller_mode(ctrl); - spd_set_dram_timing(ctrl); - spd_set_dram_size(ctrl); - spd_set_dram_pwr_management(ctrl); - spd_set_dram_throttle_control(ctrl); - spd_set_undocumented_registers(ctrl); + return sz; }
-static void ram_command(const struct mem_controller *ctrl, - uint8_t command, - uint32_t addr) +//---------------------------------------------------------------------------------- +// Function: spd_get_supported_dimms +// Parameters: ctrl - PCI addresses of memory controller functions, and +// SMBus addresses of DIMM slots on the mainboard +// Return Value: uint8_t - a bitmask indicating which sockets contain a compatible DIMM. +// Description: Scan for compatible DIMMs. +// +static uint8_t spd_get_supported_dimms(const struct mem_controller *ctrl) { - uint32_t drc_reg; + int i; + uint8_t dimm_mask = 0; + + for (i = 0; i < DIMM_SOCKETS; i++) { + uint16_t dimm = ctrl->channel0[i]; + +#ifdef VALIDATE_DIMM_COMPATIBILITY + struct dimm_size page_size; + struct dimm_size sdram_width; +#endif + int spd_value; + + if (dimm == 0) + continue; // No such socket on this mainboard + + if (spd_read_byte(dimm, SPD_MEMORY_TYPE) != SPD_MEMORY_TYPE_SDRAM_DDR) + continue; + +#ifdef VALIDATE_DIMM_COMPATIBILITY + if ((spd_value = spd_read_byte(dimm, SPD_MODULE_VOLTAGE)) != SPD_VOLTAGE_SSTL2) { + PRINTK_DEBUG("Skipping DIMM with unsupported voltage: %02x\n", spd_value); + continue; // Unsupported voltage + } + +/* + // E7501 does not support unregistered DIMMs + spd_value = spd_read_byte(dimm, SPD_MODULE_ATTRIBUTES); + if (!(spd_value & MODULE_REGISTERED) || (spd_value < 0)) { + PRINTK_DEBUG("Skipping unregistered DIMM: %02x\n", spd_value); + continue; + } +*/ + + page_size = sdram_spd_get_page_size(dimm); + sdram_width = sdram_spd_get_width(dimm); + + // Validate DIMM page size + // The i855 only supports page sizes of 4, 8, 16 KB per channel + // NOTE: 4 KB = 32 Kb = 2^15 + // 16 KB = 128 Kb = 2^17 + + if ((page_size.side1 < 15) || (page_size.side1 > 17)) { + PRINTK_DEBUG("Skipping DIMM with unsupported page size: %d\n", page_size.side1); + continue; + } + + // If DIMM is double-sided, verify side2 page size + if (page_size.side2 != 0) { + if ((page_size.side2 < 15) || (page_size.side2 > 17)) { + PRINTK_DEBUG("Skipping DIMM with unsupported page size: %d\n", page_size.side2); + continue; + } + } + // Validate SDRAM width + // The i855 only supports x8 and x16 devices + if ((sdram_width.side1 != 8) && (sdram_width.side1 != 16)) { + PRINTK_DEBUG("Skipping DIMM with unsupported width: %d\n", sdram_width.side2); + continue; + } + + // If DIMM is double-sided, verify side2 width + if (sdram_width.side2 != 0) { + if ((sdram_width.side2 != 8) + && (sdram_width.side2 != 16)) { + PRINTK_DEBUG("Skipping DIMM with unsupported width: %d\n", sdram_width.side2); + continue; + } + } +#endif + // Made it through all the checks, this DIMM is usable + dimm_mask |= (1 << i); + }
- drc_reg = pci_read_config32(ctrl->d0, 0x70); - drc_reg &= ~(7 << 4); - drc_reg |= (command << 4); - pci_write_config8(ctrl->d0, 0x70, drc_reg); - read32(addr); + return dimm_mask; }
-static void ram_command_mrs(const struct mem_controller *ctrl, - uint8_t command, - uint32_t mode, - uint32_t addr) +/*----------------------------------------------------------------------------- +DIMM-initialization functions. +-----------------------------------------------------------------------------*/ +static void do_ram_command(uint8_t command, uint16_t jedec_mode_bits) { - uint32_t drc_reg; - uint32_t adjusted_mode; - - drc_reg = pci_read_config32(ctrl->d0, 0x70); - drc_reg &= ~(7 << 4); - drc_reg |= (command << 4); - pci_write_config8(ctrl->d0, 0x70, drc_reg); - /* Host address lines [13:3] map to DIMM address lines [11, 9:0] */ - adjusted_mode = ((mode & 0x800) << (13 - 11)) | ((mode & 0x3ff) << (12 - 9)); - print_debug("Setting mode: "); - print_debug_hex32(adjusted_mode + addr); - print_debug("\n"); - read32(adjusted_mode + addr); + int i; + u32 reg32; + uint8_t dimm_start_32M_multiple = 0; + uint16_t i855_mode_bits = jedec_mode_bits; + + /* Configure the RAM command. */ + reg32 = pci_read_config32(NORTHBRIDGE_MMC, DRC); + reg32 &= ~(7 << 4); + reg32 |= (command << 4); + PRINTK_DEBUG(" Sending RAM command 0x%08x\n", reg32); + pci_write_config32(NORTHBRIDGE_MMC, DRC, reg32); + + // RAM_COMMAND_NORMAL is an exception. + // It affects only the memory controller and does not need to be "sent" to the DIMMs. + + if (command != RAM_COMMAND_NORMAL) { + + // Send the command to all DIMMs by accessing a memory location within each + // NOTE: for mode select commands, some of the location address bits + // are part of the command + + // Map JEDEC mode bits to i855 + if (command == RAM_COMMAND_MRS || command == RAM_COMMAND_EMRS) { + /* Host address lines [13:3] map to DIMM address lines [11, 9:0] */ + i855_mode_bits = ((jedec_mode_bits & 0x800) << (13 - 11)) | ((jedec_mode_bits & 0x3ff) << (12 - 9)); + } + + for (i = 0; i < (DIMM_SOCKETS * 2); ++i) { + uint8_t dimm_end_32M_multiple = pci_read_config8(NORTHBRIDGE_MMC, DRB + i); + if (dimm_end_32M_multiple > dimm_start_32M_multiple) { + + uint32_t dimm_start_address = dimm_start_32M_multiple << 25; + PRINTK_DEBUG(" Sending RAM command to 0x%08x\n", dimm_start_address + i855_mode_bits); + read32(dimm_start_address + i855_mode_bits); + + // Set the start of the next DIMM + dimm_start_32M_multiple = dimm_end_32M_multiple; + } + } + } }
static void set_initialize_complete(const struct mem_controller *ctrl) { uint32_t drc_reg;
- drc_reg = pci_read_config32(ctrl->d0, 0x70); + drc_reg = pci_read_config32(NORTHBRIDGE_MMC, DRC); drc_reg |= (1 << 29); - pci_write_config32(ctrl->d0, 0x70, drc_reg); + pci_write_config32(NORTHBRIDGE_MMC, DRC, drc_reg); }
static void sdram_enable(int controllers, const struct mem_controller *ctrl) { int i; - uint32_t rank1 = (1 << 30) / 2; + print_debug("Ram enable 1\n"); delay(); delay();
- print_debug("Ram enable 2\n"); - ram_command(ctrl, 1, 0); - ram_command(ctrl, 1, rank1); + /* NOP command */ + PRINTK_DEBUG(" NOP\n"); + do_ram_command(RAM_COMMAND_NOP, 0); + delay(); delay(); delay();
- print_debug("Ram enable 3\n"); - ram_command(ctrl, 2, 0); - ram_command(ctrl, 2, rank1); + /* Pre-charge all banks (at least 200 us after NOP) */ + PRINTK_DEBUG(" Pre-charging all banks\n"); + do_ram_command(RAM_COMMAND_PRECHARGE, 0); + delay(); delay(); delay();
print_debug("Ram enable 4\n"); - ram_command_mrs(ctrl, 4, SDRAM_EXTMODE_DLL_ENABLE, 0); - ram_command_mrs(ctrl, 4, SDRAM_EXTMODE_DLL_ENABLE, rank1); + do_ram_command(RAM_COMMAND_EMRS, SDRAM_EXTMODE_DLL_ENABLE); + delay(); delay(); delay();
print_debug("Ram enable 5\n"); - ram_command_mrs(ctrl, 3, VG85X_MODE | SDRAM_MODE_DLL_RESET, 0); - ram_command_mrs(ctrl, 3, VG85X_MODE | SDRAM_MODE_DLL_RESET, rank1); + do_ram_command(RAM_COMMAND_MRS, VG85X_MODE | SDRAM_MODE_DLL_RESET);
print_debug("Ram enable 6\n"); - ram_command(ctrl, 2, 0); - ram_command(ctrl, 2, rank1); + do_ram_command(RAM_COMMAND_PRECHARGE, 0); + delay(); delay(); delay();
- print_debug("Ram enable 7\n"); + /* 8 CBR refreshes (Auto Refresh) */ + PRINTK_DEBUG(" 8 CBR refreshes\n"); for(i = 0; i < 8; i++) { - ram_command(ctrl, 6, 0); - ram_command(ctrl, 6, rank1); + do_ram_command(RAM_COMMAND_CBR, 0); + delay(); delay(); delay(); }
print_debug("Ram enable 8\n"); - ram_command_mrs(ctrl, 3, VG85X_MODE | SDRAM_MODE_NORMAL, 0); - ram_command_mrs(ctrl, 3, VG85X_MODE | SDRAM_MODE_NORMAL, rank1); + do_ram_command(RAM_COMMAND_MRS, VG85X_MODE | SDRAM_MODE_NORMAL);
- print_debug("Ram enable 9\n"); - ram_command(ctrl, 7, 0); - ram_command(ctrl, 7, rank1); + /* Set GME-M Mode Select bits back to NORMAL operation mode */ + PRINTK_DEBUG(" Normal operation mode\n"); + do_ram_command(RAM_COMMAND_NORMAL, 0); + delay(); delay(); delay();
@@ -277,6 +473,8 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl) delay(); delay(); delay(); + delay(); + delay();
print_debug("After configuration:\n"); /* dump_pci_devices(); */ @@ -287,3 +485,497 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl) ram_check(0x100000, 0x40000000); */ } + +/*----------------------------------------------------------------------------- +DIMM-independant configuration functions. +-----------------------------------------------------------------------------*/ + +/** + * Set only what I need until it works, then make it figure things out on boot + * assumes only one dimm is populated + */ + +static void sdram_set_registers(const struct mem_controller *ctrl) +{ + /* + print_debug("Before configuration:\n"); + dump_pci_devices(); + */ +} + +static void spd_set_row_attributes(const struct mem_controller *ctrl, uint8_t dimm_mask) +{ + int i; + uint16_t row_attributes = 0; + + for (i = 0; i < DIMM_SOCKETS; i++) { + uint16_t dimm = ctrl->channel0[i]; + struct dimm_size page_size; + struct dimm_size sdram_width; + + if (!(dimm_mask & (1 << i))) { + row_attributes |= 0x77 << (i << 3); + continue; // This DIMM not usable + } + + // Get the relevant parameters via SPD + page_size = sdram_spd_get_page_size(dimm); + sdram_width = sdram_spd_get_width(dimm); + + // Update the DRAM Row Attributes. + // Page size is encoded as log2(page size in bits) - log2(2 KB) or 4 KB == 1, 8 KB == 3, 16KB == 3 + // NOTE: 2 KB = 16 Kb = 2^14 + row_attributes |= (page_size.side1 - 14) << (i << 3); // Side 1 of each DIMM is an EVEN row + + if (sdram_width.side2 > 0) + row_attributes |= (page_size.side2 - 14) << ((i << 3) + 4); // Side 2 is ODD + else + row_attributes |= 7 << ((i << 3) + 4); + /* go to the next DIMM */ + } + + PRINTK_DEBUG("DRA: %04x\n", row_attributes); + + /* Write the new row attributes register */ + pci_write_config16(NORTHBRIDGE_MMC, DRA, row_attributes); +} + +static void spd_set_dram_controller_mode(const struct mem_controller *ctrl, uint8_t dimm_mask) +{ + int i; + + // Initial settings + u32 controller_mode = pci_read_config32(NORTHBRIDGE_MMC, DRC); + u32 system_refresh_mode = (controller_mode >> 7) & 7; + + controller_mode |= (1 << 20); // ECC + controller_mode |= (1 << 15); // RAS lockout + controller_mode |= (1 << 12); // Address Tri-state enable (ADRTRIEN), FIXME: how is this detected????? + controller_mode |= (2 << 10); // FIXME: Undocumented, really needed????? + + for (i = 0; i < DIMM_SOCKETS; i++) { + uint16_t dimm = ctrl->channel0[i]; + uint32_t dimm_refresh_mode; + int value; + u8 tRCD, tRP; + + if (!(dimm_mask & (1 << i))) { + continue; // This DIMM not usable + } + + // Disable ECC mode if any one of the DIMMs does not support ECC + value = spd_read_byte(dimm, SPD_DIMM_CONFIG_TYPE); + die_on_spd_error(value); + if (value != ERROR_SCHEME_ECC) + controller_mode &= ~(3 << 20); + + value = spd_read_byte(dimm, SPD_REFRESH); + die_on_spd_error(value); + value &= 0x7f; // Mask off self-refresh bit + if (value > MAX_SPD_REFRESH_RATE) { + print_err("unsupported refresh rate\n"); + continue; + } + // Get the appropriate i855 refresh mode for this DIMM + dimm_refresh_mode = refresh_rate_map[value]; + if (dimm_refresh_mode > 7) { + print_err("unsupported refresh rate\n"); + continue; + } + // If this DIMM requires more frequent refresh than others, + // update the system setting + if (refresh_frequency[dimm_refresh_mode] > + refresh_frequency[system_refresh_mode]) + system_refresh_mode = dimm_refresh_mode; + + /* FIXME: is this correct? */ + tRCD = spd_read_byte(dimm, SPD_tRCD); + tRP = spd_read_byte(dimm, SPD_tRP); + if (tRCD != tRP) { + PRINTK_DEBUG(" Disabling RAS lockouk due to tRCD (%d) != tRP (%d)\n", tRCD, tRP); + controller_mode &= ~(1 << 15); + } + + /* go to the next DIMM */ + } + + controller_mode &= ~(7 << 7); + controller_mode |= (system_refresh_mode << 7); + PRINTK_DEBUG("DRC: %08x\n", controller_mode); + + pci_write_config32(NORTHBRIDGE_MMC, DRC, controller_mode); +} + +static void spd_set_dram_timing(const struct mem_controller *ctrl, uint8_t dimm_mask) +{ + int i; + u32 dram_timing; + + // CAS# latency bitmasks in SPD_ACCEPTABLE_CAS_LATENCIES format + // NOTE: i82822 supports only 2.0 and 2.5 + uint32_t system_compatible_cas_latencies = SPD_CAS_LATENCY_2_0 | SPD_CAS_LATENCY_2_5; + uint8_t slowest_row_precharge = 0; + uint8_t slowest_ras_cas_delay = 0; + uint8_t slowest_active_to_precharge_delay = 0; + + for (i = 0; i < DIMM_SOCKETS; i++) { + uint16_t dimm = ctrl->channel0[i]; + int value; + uint32_t current_cas_latency; + uint32_t dimm_compatible_cas_latencies; + if (!(dimm_mask & (1 << i))) + continue; // This DIMM not usable + + value = spd_read_byte(dimm, SPD_ACCEPTABLE_CAS_LATENCIES); + PRINTK_DEBUG("SPD_ACCEPTABLE_CAS_LATENCIES: %d\n", value); + die_on_spd_error(value); + + dimm_compatible_cas_latencies = value & 0x7f; // Start with all supported by DIMM + PRINTK_DEBUG("dimm_compatible_cas_latencies #1: %d\n", dimm_compatible_cas_latencies); + + current_cas_latency = 1 << log2(dimm_compatible_cas_latencies); // Max supported by DIMM + PRINTK_DEBUG("current_cas_latency: %d\n", current_cas_latency); + + // Can we support the highest CAS# latency? + value = spd_read_byte(dimm, SPD_MIN_CYCLE_TIME_AT_CAS_MAX); + die_on_spd_error(value); + PRINTK_DEBUG("SPD_MIN_CYCLE_TIME_AT_CAS_MAX: %d.%d\n", value >> 4, value & 0xf); + + // NOTE: At 133 MHz, 1 clock == 7.52 ns + if (value > 0x75) { + // Our bus is too fast for this CAS# latency + // Remove it from the bitmask of those supported by the DIMM that are compatible + dimm_compatible_cas_latencies &= ~current_cas_latency; + PRINTK_DEBUG("dimm_compatible_cas_latencies #2: %d\n", dimm_compatible_cas_latencies); + } + // Can we support the next-highest CAS# latency (max - 0.5)? + + current_cas_latency >>= 1; + if (current_cas_latency != 0) { + value = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_2ND); + die_on_spd_error(value); + PRINTK_DEBUG("SPD_SDRAM_CYCLE_TIME_2ND: %d.%d\n", value >> 4, value & 0xf); + if (value > 0x75) { + dimm_compatible_cas_latencies &= ~current_cas_latency; + PRINTK_DEBUG("dimm_compatible_cas_latencies #2: %d\n", dimm_compatible_cas_latencies); + } + } + // Can we support the next-highest CAS# latency (max - 1.0)? + current_cas_latency >>= 1; + if (current_cas_latency != 0) { + value = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_3RD); + PRINTK_DEBUG("SPD_SDRAM_CYCLE_TIME_3RD: %d.%d\n", value >> 4, value & 0xf); + die_on_spd_error(value); + if (value > 0x75) { + dimm_compatible_cas_latencies &= ~current_cas_latency; + PRINTK_DEBUG("dimm_compatible_cas_latencies #2: %d\n", dimm_compatible_cas_latencies); + } + } + // Restrict the system to CAS# latencies compatible with this DIMM + system_compatible_cas_latencies &= dimm_compatible_cas_latencies; + + value = spd_read_byte(dimm, SPD_MIN_ROW_PRECHARGE_TIME); + die_on_spd_error(value); + if (value > slowest_row_precharge) + slowest_row_precharge = value; + + value = spd_read_byte(dimm, SPD_MIN_RAS_TO_CAS_DELAY); + die_on_spd_error(value); + if (value > slowest_ras_cas_delay) + slowest_ras_cas_delay = value; + + value = spd_read_byte(dimm, SPD_MIN_ACTIVE_TO_PRECHARGE_DELAY); + die_on_spd_error(value); + if (value > slowest_active_to_precharge_delay) + slowest_active_to_precharge_delay = value; + + /* go to the next DIMM */ + } + PRINTK_DEBUG("CAS latency: %d\n", system_compatible_cas_latencies); + + dram_timing = pci_read_config32(NORTHBRIDGE_MMC, DRT); + dram_timing &= ~(DRT_CAS_MASK | DRT_TRP_MASK | DRT_RCD_MASK); + PRINTK_DEBUG("DRT: %08x\n", dram_timing); + + if (system_compatible_cas_latencies & SPD_CAS_LATENCY_2_0) { + dram_timing |= DRT_CAS_2_0; + } else if (system_compatible_cas_latencies & SPD_CAS_LATENCY_2_5) { + dram_timing |= DRT_CAS_2_5; + } else + die("No CAS# latencies compatible with all DIMMs!!\n"); + + uint32_t current_cas_latency = dram_timing & DRT_CAS_MASK; + + /* tRP */ + + PRINTK_DEBUG("slowest_row_precharge: %d.%d\n", slowest_row_precharge >> 2, slowest_row_precharge & 0x3); + // i855 supports only 2, 3 or 4 clocks for tRP + if (slowest_row_precharge > ((30 << 2))) + die("unsupported DIMM tRP"); // > 30.0 ns: 5 or more clocks + else if (slowest_row_precharge > ((22 << 2) | (2 << 0))) + dram_timing |= DRT_TRP_4; // > 22.5 ns: 4 or more clocks + else if (slowest_row_precharge > (15 << 2)) + dram_timing |= DRT_TRP_3; // > 15.0 ns: 3 clocks + else + dram_timing |= DRT_TRP_2; // <= 15.0 ns: 2 clocks + + /* tRCD */ + + PRINTK_DEBUG("slowest_ras_cas_delay: %d.%d\n", slowest_ras_cas_delay >> 2, slowest_ras_cas_delay & 0x3); + // i855 supports only 2, 3 or 4 clocks for tRCD + if (slowest_ras_cas_delay > ((30 << 2))) + die("unsupported DIMM tRCD"); // > 30.0 ns: 5 or more clocks + else if (slowest_ras_cas_delay > ((22 << 2) | (2 << 0))) + dram_timing |= DRT_RCD_4; // > 22.5 ns: 4 or more clocks + else if (slowest_ras_cas_delay > (15 << 2)) + dram_timing |= DRT_RCD_3; // > 15.0 ns: 3 clocks + else + dram_timing |= DRT_RCD_2; // <= 15.0 ns: 2 clocks + + /* tRAS, min */ + + PRINTK_DEBUG("slowest_active_to_precharge_delay: %d\n", slowest_active_to_precharge_delay); + // i855 supports only 5, 6, 7 or 8 clocks for tRAS + // 5 clocks ~= 37.6 ns, 6 clocks ~= 45.1 ns, 7 clocks ~= 52.6 ns, 8 clocks ~= 60.1 ns + if (slowest_active_to_precharge_delay > 60) + die("unsupported DIMM tRAS"); // > 52 ns: 8 or more clocks + else if (slowest_active_to_precharge_delay > 52) + dram_timing |= DRT_TRAS_MIN_8; // 46-52 ns: 7 clocks + else if (slowest_active_to_precharge_delay > 45) + dram_timing |= DRT_TRAS_MIN_7; // 46-52 ns: 7 clocks + else if (slowest_active_to_precharge_delay > 37) + dram_timing |= DRT_TRAS_MIN_6; // 38-45 ns: 6 clocks + else + dram_timing |= DRT_TRAS_MIN_5; // < 38 ns: 5 clocks + + /* FIXME: guess work starts here... + * + * Intel refers to DQ turn-arround values for back to calculate the values, + * but i have no idea what this means + */ + + /* + * Back to Back Read-Write command spaceing (DDR, different Rows/Bank) + */ + /* Set to a 3 clock back to back read to write turn around. + * 2 is a good delay if the CAS latency is 2.0 */ + dram_timing &= ~(3 << 28); + if (current_cas_latency == DRT_CAS_2_0) + dram_timing |= (2 << 28); // 2 clocks + else + dram_timing |= (1 << 28); // 3 clocks + + /* + * Back to Back Read-Write command spaceing (DDR, same or different Rows/Bank) + */ + dram_timing &= ~(3 << 26); + if (current_cas_latency == DRT_CAS_2_0) + dram_timing |= (2 << 26); // 5 clocks + else + dram_timing |= (1 << 26); // 6 clocks + + /* + * Back To Back Read-Read commands spacing (DDR, different Rows): + */ + dram_timing &= ~(1 << 25); + dram_timing |= (1 << 25); // 3 clocks + + PRINTK_DEBUG("DRT: %08x\n", dram_timing); + pci_write_config32(NORTHBRIDGE_MMC, DRT, dram_timing); +} + +static void spd_set_dram_size(const struct mem_controller *ctrl, uint8_t dimm_mask) +{ + int i; + int total_dram = 0; + uint32_t drb_reg = 0; + + for (i = 0; i < DIMM_SOCKETS; i++) { + uint16_t dimm = ctrl->channel0[i]; + struct dimm_size sz; + + if (!(dimm_mask & (1 << i))) { + /* fill values even for not present DIMMs */ + drb_reg |= (total_dram << (i * 16)); + drb_reg |= (total_dram << ((i * 16) + 8)); + + continue; // This DIMM not usable + } + sz = spd_get_dimm_size(dimm); + + total_dram += (1 << (sz.side1 - 28)); + drb_reg |= (total_dram << (i * 16)); + + total_dram += (1 << (sz.side2 - 28)); + drb_reg |= (total_dram << ((i * 16) + 8)); + } + PRINTK_DEBUG("DRB: %08x\n", drb_reg); + pci_write_config32(NORTHBRIDGE_MMC, DRB, drb_reg); +} + + +static void spd_set_dram_pwr_management(const struct mem_controller *ctrl) +{ + uint32_t pwrmg_reg; + + pwrmg_reg = 0x10f10430; + pci_write_config32(NORTHBRIDGE_MMC, PWRMG, pwrmg_reg); +} + +static void spd_set_dram_throttle_control(const struct mem_controller *ctrl) +{ + uint32_t dtc_reg = 0; + + /* DDR SDRAM Throttle Mode (TMODE): + * 0011 = Both Rank and GMCH Thermal Sensor based throttling is enabled. When the external SO- + * DIMM Thermal Sensor is Tripped DDR SDRAM Throttling begins based on the setting in RTT + */ + dtc_reg |= (3 << 28); + + /* Read Counter Based Power Throttle Control (RCTC): + * 0 = 85% + */ + dtc_reg |= (0 << 24); + + /* Write Counter Based Power Throttle Control (WCTC): + * 0 = 85% + */ + dtc_reg |= (0 << 20); + + /* Read Thermal Based Power Throttle Control (RTTC): + * 0xA = 20% + */ + dtc_reg |= (0xA << 16); + + /* Write Thermal Based Power Throttle Control (WTTC): + * 0xA = 20% + */ + dtc_reg |= (0xA << 12); + + /* Counter Based Throttle Lock (CTLOCK): */ + dtc_reg |= (0 << 11); + + /* Thermal Throttle Lock (TTLOCK): */ + dtc_reg |= (0 << 10); + + /* Thermal Power Throttle Control fields Enable: */ + dtc_reg |= (1 << 9); + + /* High Priority Stream Throttling Enable: */ + dtc_reg |= (0 << 8); + + /* Global DDR SDRAM Sampling Window (GDSW): */ + dtc_reg |= 0xff; + PRINTK_DEBUG("DTC: %08x\n", dtc_reg); + pci_write_config32(NORTHBRIDGE_MMC, DTC, dtc_reg); +} + +static void spd_update(const struct mem_controller *ctrl, u8 reg, u32 new_value) +{ + u32 value1 = pci_read_config32(ctrl->d0, reg); + pci_write_config32(ctrl->d0, reg, new_value); + u32 value2 = pci_read_config32(ctrl->d0, reg); + PRINTK_DEBUG("update reg %02x, old: %08x, new: %08x, read back: %08x\n", reg, value1, new_value, value2); +} + +/* if ram still doesn't work do this function */ +static void spd_set_undocumented_registers(const struct mem_controller *ctrl) +{ + spd_update(ctrl, 0x74, 0x00000001); + spd_update(ctrl, 0x78, 0x001fe974); + spd_update(ctrl, 0x80, 0x00af0039); + spd_update(ctrl, 0x84, 0x0000033c); + spd_update(ctrl, 0x88, 0x00000010); + + spd_update(ctrl, 0xc0, 0x00000003); +} + +static void northbridge_set_registers(void) +{ + u16 value; + int video_memory = 0; + + printk(BIOS_DEBUG, "Setting initial Northbridge registers....\n"); + + /* Set the value for Fixed DRAM Hole Control Register */ + pci_write_config8(NORTHBRIDGE, FDHC, 0x00); + + /* Set the value for Programable Attribute Map Registers + * Ideally, this should be R/W for as many ranges as possible. + */ + pci_write_config8(NORTHBRIDGE, PAM0, 0x30); + pci_write_config8(NORTHBRIDGE, PAM1, 0x33); + pci_write_config8(NORTHBRIDGE, PAM2, 0x33); + pci_write_config8(NORTHBRIDGE, PAM3, 0x33); + pci_write_config8(NORTHBRIDGE, PAM4, 0x33); + pci_write_config8(NORTHBRIDGE, PAM5, 0x33); + pci_write_config8(NORTHBRIDGE, PAM6, 0x33); + + /* Set the value for System Management RAM Control Register */ + pci_write_config8(NORTHBRIDGE, SMRAM, 0x02); + + /* Set the value for GMCH Control Register #1 */ + switch (CONFIG_VIDEO_MB) { + case 1: /* 1M of memory */ + video_memory = 0x1; + break; + case 4: /* 4M of memory */ + video_memory = 0x2; + break; + case 8: /* 8M of memory */ + video_memory = 0x3; + break; + case 16: /* 16M of memory */ + video_memory = 0x4; + break; + case 32: /* 32M of memory */ + video_memory = 0x5; + break; + default: /* No memory */ + pci_write_config16(NORTHBRIDGE, GMC, pci_read_config16(NORTHBRIDGE, GMC) | 1); + video_memory = 0x0; + } + + value = pci_read_config16(NORTHBRIDGE, GGC); + value |= video_memory << 4; + if (video_memory == 0) { + value &= ~(1 < 1); + } else + value |= (1 < 1); + pci_write_config16(NORTHBRIDGE, GGC, value); + + /* AGPCMD: disable AGP, Data-Rate: 1x */ + pci_write_config32(NORTHBRIDGE, AGPCMD, 0x00000001); + + pci_write_config8(NORTHBRIDGE, AMTT, 0x20); + pci_write_config8(NORTHBRIDGE, LPTT, 0x10); + + printk(BIOS_DEBUG, "Initial Northbridge registers have been set.\n"); +} + +static void sdram_set_spd_registers(const struct mem_controller *ctrl) +{ + uint8_t dimm_mask; + + PRINTK_DEBUG("Reading SPD data...\n"); + + dimm_mask = spd_get_supported_dimms(ctrl); + + if (dimm_mask == 0) { + print_debug("No usable memory for this controller\n"); + } else { + PRINTK_DEBUG("DIMM MASK: %02x\n", dimm_mask); + + spd_set_row_attributes(ctrl, dimm_mask); + spd_set_dram_controller_mode(ctrl, dimm_mask); + spd_set_dram_timing(ctrl, dimm_mask); + spd_set_dram_size(ctrl, dimm_mask); + spd_set_dram_pwr_management(ctrl); + spd_set_dram_throttle_control(ctrl); + spd_set_undocumented_registers(ctrl); + } + + /* Setup Initial Northbridge Registers */ + northbridge_set_registers(); +} + diff --git a/src/northbridge/intel/i855/raminit.h b/src/northbridge/intel/i855/raminit.h index dbd0be6..1f1b34d 100644 --- a/src/northbridge/intel/i855/raminit.h +++ b/src/northbridge/intel/i855/raminit.h @@ -18,11 +18,19 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#ifndef RAMINIT_H -#define RAMINIT_H +#ifndef NORTHBRIDGE_INTEL_I855_RAMINIT_H +#define NORTHBRIDGE_INTEL_I855_RAMINIT_H
+/* i855 Northbridge PCI device */ +#define NORTHBRIDGE PCI_DEV(0, 0, 0) +#define NORTHBRIDGE_MMC PCI_DEV(0, 0, 1) + +/* The i855 supports max. 2 dual-sided SO-DIMMs. */ #define DIMM_SOCKETS 2
+/* DIMM0 is at 0x50, DIMM1 is at 0x51. */ +#define DIMM_SPD_BASE 0x50 + struct mem_controller { device_t d0; uint16_t channel0[DIMM_SOCKETS]; @@ -31,4 +39,4 @@ struct mem_controller { void sdram_initialize(int controllers, const struct mem_controller *ctrl);
-#endif /* RAMINIT_H */ +#endif /* NORTHBRIDGE_INTEL_I855_RAMINIT_H */
Signed-off-by: Andreas Schultz aschultz@tpip.net --- src/mainboard/Kconfig | 8 ++ src/mainboard/lanner/Kconfig | 8 ++ src/mainboard/lanner/em8510/Kconfig | 38 +++++++++++ src/mainboard/lanner/em8510/Makefile.inc | 21 ++++++ src/mainboard/lanner/em8510/chip.h | 23 +++++++ src/mainboard/lanner/em8510/cmos.layout | 74 +++++++++++++++++++++ src/mainboard/lanner/em8510/devicetree.cb | 60 +++++++++++++++++ src/mainboard/lanner/em8510/irq_tables.c | 56 ++++++++++++++++ src/mainboard/lanner/em8510/mainboard.c | 27 ++++++++ src/mainboard/lanner/em8510/romstage.c | 103 +++++++++++++++++++++++++++++ 10 files changed, 418 insertions(+), 0 deletions(-) create mode 100644 src/mainboard/lanner/Kconfig create mode 100644 src/mainboard/lanner/em8510/Kconfig create mode 100644 src/mainboard/lanner/em8510/Makefile.inc create mode 100644 src/mainboard/lanner/em8510/chip.h create mode 100644 src/mainboard/lanner/em8510/cmos.layout create mode 100644 src/mainboard/lanner/em8510/devicetree.cb create mode 100644 src/mainboard/lanner/em8510/irq_tables.c create mode 100644 src/mainboard/lanner/em8510/mainboard.c create mode 100644 src/mainboard/lanner/em8510/romstage.c
diff --git a/src/mainboard/Kconfig b/src/mainboard/Kconfig index a562db2..7f97fc6 100644 --- a/src/mainboard/Kconfig +++ b/src/mainboard/Kconfig @@ -64,6 +64,8 @@ config VENDOR_JETWAY bool "Jetway" config VENDOR_KONTRON bool "Kontron" +config VENDOR_LANNER + bool "Lanner" config VENDOR_LIPPERT bool "Lippert" config VENDOR_MITAC @@ -270,6 +272,11 @@ config MAINBOARD_VENDOR
config MAINBOARD_VENDOR string + default "Lanner" + depends on VENDOR_LANNER + +config MAINBOARD_VENDOR + string default "Lippert" depends on VENDOR_LIPPERT
@@ -443,6 +450,7 @@ source "src/mainboard/intel/Kconfig" source "src/mainboard/iwill/Kconfig" source "src/mainboard/jetway/Kconfig" source "src/mainboard/kontron/Kconfig" +source "src/mainboard/lanner/Kconfig" source "src/mainboard/lippert/Kconfig" source "src/mainboard/mitac/Kconfig" source "src/mainboard/msi/Kconfig" diff --git a/src/mainboard/lanner/Kconfig b/src/mainboard/lanner/Kconfig new file mode 100644 index 0000000..f499efa --- /dev/null +++ b/src/mainboard/lanner/Kconfig @@ -0,0 +1,8 @@ +choice + prompt "Mainboard model" + depends on VENDOR_LANNER + +source "src/mainboard/lanner/em8510/Kconfig" + +endchoice + diff --git a/src/mainboard/lanner/em8510/Kconfig b/src/mainboard/lanner/em8510/Kconfig new file mode 100644 index 0000000..97d2949 --- /dev/null +++ b/src/mainboard/lanner/em8510/Kconfig @@ -0,0 +1,38 @@ +config BOARD_LANNER_EM8510 + bool "EM-8510" + select ARCH_X86 + select CPU_INTEL_SOCKET_MPGA479M + select NORTHBRIDGE_INTEL_I855 + select SOUTHBRIDGE_INTEL_I82801DX + select SUPERIO_WINBOND_W83627THF + select HAVE_OPTION_TABLE + select HAVE_PIRQ_TABLE + select HAVE_HARD_RESET + select BOARD_ROMSIZE_KB_512 + select USE_DCACHE_RAM + select TINY_BOOTBLOCK + +config MAINBOARD_DIR + string + default lanner/em8510 + depends on BOARD_LANNER_EM8510 + +config MAINBOARD_PART_NUMBER + string + default "EM-8510" + depends on BOARD_LANNER_EM8510 + +config DCACHE_RAM_BASE + hex + default 0xffdf8000 + depends on BOARD_LANNER_EM8510 + +config DCACHE_RAM_SIZE + hex + default 0x8000 + depends on BOARD_LANNER_EM8510 + +config IRQ_SLOT_COUNT + int + default 10 + depends on BOARD_LANNER_EM8510 diff --git a/src/mainboard/lanner/em8510/Makefile.inc b/src/mainboard/lanner/em8510/Makefile.inc new file mode 100644 index 0000000..6b93f64 --- /dev/null +++ b/src/mainboard/lanner/em8510/Makefile.inc @@ -0,0 +1,21 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2010 Travelping GmbH info@travelping.com +## +## 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; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +ROMCCFLAGS := -mcpu=p3 -O diff --git a/src/mainboard/lanner/em8510/chip.h b/src/mainboard/lanner/em8510/chip.h new file mode 100644 index 0000000..96d8705 --- /dev/null +++ b/src/mainboard/lanner/em8510/chip.h @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Travelping GmbH info@travelping.com + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +extern struct chip_operations mainboard_ops; + +struct mainboard_config {}; diff --git a/src/mainboard/lanner/em8510/cmos.layout b/src/mainboard/lanner/em8510/cmos.layout new file mode 100644 index 0000000..c1354a2 --- /dev/null +++ b/src/mainboard/lanner/em8510/cmos.layout @@ -0,0 +1,74 @@ +entries + +#start-bit length config config-ID name +#0 8 r 0 seconds +#8 8 r 0 alarm_seconds +#16 8 r 0 minutes +#24 8 r 0 alarm_minutes +#32 8 r 0 hours +#40 8 r 0 alarm_hours +#48 8 r 0 day_of_week +#56 8 r 0 day_of_month +#64 8 r 0 month +#72 8 r 0 year +#80 4 r 0 rate_select +#84 3 r 0 REF_Clock +#87 1 r 0 UIP +#88 1 r 0 auto_switch_DST +#89 1 r 0 24_hour_mode +#90 1 r 0 binary_values_enable +#91 1 r 0 square-wave_out_enable +#92 1 r 0 update_finished_enable +#93 1 r 0 alarm_interrupt_enable +#94 1 r 0 periodic_interrupt_enable +#95 1 r 0 disable_clock_updates +#96 288 r 0 temporary_filler +0 384 r 0 reserved_memory +384 1 e 4 boot_option +385 1 e 4 last_boot +386 1 e 1 ECC_memory +388 4 r 0 reboot_bits +392 3 e 5 baud_rate +400 1 e 1 power_on_after_fail +412 4 e 6 debug_level +416 4 e 7 boot_first +420 4 e 7 boot_second +424 4 e 7 boot_third +428 4 h 0 boot_index +432 8 h 0 boot_countdown +1008 16 h 0 check_sum + +enumerations + +#ID value text +1 0 Disable +1 1 Enable +2 0 Enable +2 1 Disable +4 0 Fallback +4 1 Normal +5 0 115200 +5 1 57600 +5 2 38400 +5 3 19200 +5 4 9600 +5 5 4800 +5 6 2400 +5 7 1200 +6 6 Notice +6 7 Info +6 8 Debug +6 9 Spew +7 0 Network +7 1 HDD +7 2 Floppy +7 8 Fallback_Network +7 9 Fallback_HDD +7 10 Fallback_Floppy +#7 3 ROM + +checksums + +checksum 392 1007 1008 + + diff --git a/src/mainboard/lanner/em8510/devicetree.cb b/src/mainboard/lanner/em8510/devicetree.cb new file mode 100644 index 0000000..7df1443 --- /dev/null +++ b/src/mainboard/lanner/em8510/devicetree.cb @@ -0,0 +1,60 @@ +chip northbridge/intel/i855 + device pci_domain 0 on + device pci 0.0 on end + chip southbridge/intel/i82801dx +# pci 11.0 on end +# pci 11.1 on end +# pci 11.2 on end +# pci 11.3 on end +# pci 11.4 on end +# pci 11.5 on end +# pci 11.6 on end +# pci 12.0 on end + register "enable_usb" = "0" + register "enable_native_ide" = "0" + device pci 1f.0 on + chip superio/winbond/w83627thf # link 1 + device pnp 2e.0 on # Floppy + io 0x60 = 0x3f0 + irq 0x70 = 6 + drq 0x74 = 2 + end + device pnp 2e.1 on # Parallel Port + io 0x60 = 0x378 + irq 0x70 = 7 + end + device pnp 2e.2 on # Com1 + io 0x60 = 0x3f8 + irq 0x70 = 4 + end + device pnp 2e.3 on # Com2 + io 0x60 = 0x2f8 + irq 0x70 = 3 + end + device pnp 2e.5 on # Keyboard + io 0x60 = 0x60 + io 0x62 = 0x64 + irq 0x70 = 1 + irq 0x72 = 12 + end + device pnp 2e.6 off end # CIR + device pnp 2e.7 off end # GAME_MIDI_GIPO1 + device pnp 2e.8 off end # GPIO2 + device pnp 2e.9 off end # GPIO3 + device pnp 2e.a off end # ACPI + device pnp 2e.b on # HW Monitor + io 0x60 = 0x290 + end + register "com1" = "{1}" + # register "com1" = "{1, 0, 0x3f8, 4}" + # register "lpt" = "{1}" + end + end + end + end + device lapic_cluster 0 on + chip cpu/intel/socket_mPGA479M + device lapic 0 on end + end + end +end diff --git a/src/mainboard/lanner/em8510/irq_tables.c b/src/mainboard/lanner/em8510/irq_tables.c new file mode 100644 index 0000000..5b42952 --- /dev/null +++ b/src/mainboard/lanner/em8510/irq_tables.c @@ -0,0 +1,56 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Travelping GmbH info@travelping.com + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <arch/pirq_routing.h> + +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32 + 16 * 10, /* Max. number of devices on the bus */ + 0x00, /* Interrupt router bus */ + (0x1f << 3) | 0x0, /* Interrupt router dev */ + 0x1e20, /* IRQs devoted exclusively to PCI usage */ + 0x8086, /* Vendor */ + 0x24cc, /* Device */ + 0, /* Miniport */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0x39, /* Checksum (has to be set to some value that + * would give 0 after the sum of all bytes + * for this structure (including checksum). + */ + { + /* bus, dev | fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */ + {0x01, (0x0f << 3) | 0x0, {{0x62, 0xdeb8}, {0x63, 0xdeb8}, {0x60, 0xdeb8}, {0x61, 0xdeb8}}, 0x1, 0x0}, + {0x01, (0x0a << 3) | 0x0, {{0x62, 0xdeb8}, {0x63, 0xdeb8}, {0x60, 0xdeb8}, {0x61, 0xdeb8}}, 0x2, 0x0}, + {0x01, (0x05 << 3) | 0x0, {{0x68, 0xdeb8}, {0x69, 0xdeb8}, {0x6a, 0xdeb8}, {0x6b, 0xdeb8}}, 0x3, 0x0}, + {0x01, (0x06 << 3) | 0x0, {{0x69, 0xdeb8}, {0x6a, 0xdeb8}, {0x6b, 0xdeb8}, {0x68, 0xdeb8}}, 0x4, 0x0}, + {0x01, (0x07 << 3) | 0x0, {{0x6a, 0xdeb8}, {0x6b, 0xdeb8}, {0x68, 0xdeb8}, {0x69, 0xdeb8}}, 0x5, 0x0}, + {0x01, (0x09 << 3) | 0x0, {{0x6b, 0xdeb8}, {0x68, 0xdeb8}, {0x69, 0xdeb8}, {0x6a, 0xdeb8}}, 0x6, 0x0}, + {0x00, (0x1e << 3) | 0x0, {{0x60, 0xdeb8}, {0x61, 0xdeb8}, {0x62, 0xdeb8}, {0x63, 0xdeb8}}, 0x0, 0x0}, + {0x00, (0x02 << 3) | 0x0, {{0x60, 0xdeb8}, {0x60, 0xdeb8}, {0x60, 0xdeb8}, {0x60, 0xdeb8}}, 0x0, 0x0}, + {0x00, (0x1f << 3) | 0x0, {{0x62, 0xdeb8}, {0x61, 0xdeb8}, {0x60, 0xdeb8}, {0x63, 0xdeb8}}, 0x0, 0x0}, + {0x00, (0x1d << 3) | 0x0, {{0x60, 0xdeb8}, {0x63, 0xdeb8}, {0x62, 0xdeb8}, {0x6b, 0xdeb8}}, 0x0, 0x0}, + } +}; + +unsigned long write_pirq_routing_table(unsigned long addr) +{ + return copy_pirq_routing_table(addr); +} diff --git a/src/mainboard/lanner/em8510/mainboard.c b/src/mainboard/lanner/em8510/mainboard.c new file mode 100644 index 0000000..4a20d25 --- /dev/null +++ b/src/mainboard/lanner/em8510/mainboard.c @@ -0,0 +1,27 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Travelping GmbH info@travelping.com + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <device/device.h> +#include "chip.h" + +struct chip_operations mainboard_ops = { + CHIP_NAME("LANNER EM-8510 Mainboard") +}; + diff --git a/src/mainboard/lanner/em8510/romstage.c b/src/mainboard/lanner/em8510/romstage.c new file mode 100644 index 0000000..9a33fa8 --- /dev/null +++ b/src/mainboard/lanner/em8510/romstage.c @@ -0,0 +1,103 @@ +/* + * This file is part of the coreboot project. + * + * Original take from digitallogic/adl855pc + * + * Copyright (C) 2010 Travelping GmbH info@travelping.com + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> +#include <device/pci_def.h> +#include <arch/io.h> +#include <device/pnp_def.h> +#include <arch/romcc_io.h> +#include <arch/hlt.h> +#include <stdlib.h> +#include "pc80/udelay_io.c" +#include <pc80/mc146818rtc.h> +#include <console/console.h> +#include "lib/ramtest.c" +#include "southbridge/intel/i82801dx/i82801dx.h" +#include "southbridge/intel/i82801dx/i82801dx_early_smbus.c" +#include "northbridge/intel/i855/raminit.h" +#include "northbridge/intel/i855/debug.c" +#include "superio/winbond/w83627thf/w83627thf_early_serial.c" +#include "cpu/x86/mtrr/earlymtrr.c" +#include "cpu/x86/bist.h" + +#define SERIAL_DEV PNP_DEV(0x2e, W83627THF_SP1) + +static inline int spd_read_byte(unsigned device, unsigned address) +{ + return smbus_read_byte(device, address); +} + +#include "northbridge/intel/i855/raminit.c" +#include "northbridge/intel/i855/reset_test.c" +#include "lib/generic_sdram.c" + +void main(unsigned long bist) +{ + static const struct mem_controller memctrl[] = { + { + .d0 = PCI_DEV(0, 0, 1), + .channel0 = { (0xa<<3)|0, 0 }, + }, + }; + + if (bist == 0) { +#if 0 + enable_lapic(); + init_timer(); +#endif + } + + w83627thf_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE); + uart_init(); + console_init(); + + /* Halt if there was a built in self test failure */ + report_bist_failure(bist); + +#if 0 + print_pci_devices(); +#endif + + if(!bios_reset_detected()) { + enable_smbus(); +#if 1 + dump_spd_registers(&memctrl[0]); + dump_smbus_registers(); +#endif + + sdram_initialize(ARRAY_SIZE(memctrl), memctrl); + + } + +#if 0 + dump_pci_devices(); + dump_pci_device(PCI_DEV(0, 0, 0)); + + // Check all of memory + ram_check(0x00000000, msr.lo+(msr.hi<<32)); + // Check 16MB of memory @ 0 + ram_check(0x00000000, 0x01000000); + // Check 16MB of memory @ 2GB + ram_check(0x80000000, 0x81000000); +#endif +} +
On 8/30/10 12:10 PM, Andreas Schultz wrote:
Signed-off-by: Andreas Schultz aschultz@tpip.net
Dear Andreas,
glad to see you had some success with coreboot!
thank you very much for your contributions!
I checked in your patches in r5750-r5753
Best regards, Stefan
2010/8/30 Andreas Schultz aschultz@tpip.net
Hi,
Here is a series of patches wich improve i855 support and a new board with that chipset.
The board boots successfully with Seabios into Linux!
Nice work. Can you show the output from the console (serial output) ?
Off topic: I'm asking this because I own a P4 CPU, with the CPU id 0x0f29 (ergo it's not a Celeron M), that I can't get to start using CAR. Different but similar chipset:Intel i865.
There are still a few blacks left to filled in (undocumented chipset registers, some RAM parameters i have no idea how to compute). So any comment is welcome!
Regards Andreas
-- Dipl. Inform. Andreas Schultz
email: as@travelping.com phone: +49-391-819099-224
------------------ managed broadband access ------------------
Travelping GmbH phone: +49-391-8190990 Roentgenstr. 13 fax: +49-391-819099299 D-39108 Magdeburg email: info@travelping.com GERMANY web: http://www.travelping.com
Company Registration: Amtsgericht Stendal Reg No.: HRB 10578 Geschaeftsfuehrer: Holger Winkelmann | VAT ID No.: DE236673780
-- coreboot mailing list: coreboot@coreboot.org http://www.coreboot.org/mailman/listinfo/coreboot