Alexandru Gagniuc (mr.nuke.me(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/171
-gerrit
commit c28dcca158728bcb540f2f0acf62a78bb1e2925a
Author: Alexandru Gagniuc <mr.nuke.me(a)gmail.com>
Date: Wed Aug 24 23:11:44 2011 -0500
NOTFORMERGE: vx900 (not-yet-functional) raminit
Change-Id: I38193572bf0416fd642002dba94c19257f0f6f5b
Signed-off-by: Alexandru Gagniuc <mr.nuke.me(a)gmail.com>
---
src/devices/dram/dram.h | 149 +++++
src/devices/dram/dram_util.c | 297 +++++++++
src/devices/smbus/early_smbus.c | 141 +++++
src/devices/smbus/smbus.h | 99 +++
src/mainboard/via/epia-m850/.directory | 4 +
src/mainboard/via/epia-m850/Kconfig | 47 ++
src/mainboard/via/epia-m850/Makefile.inc | 21 +
src/mainboard/via/epia-m850/chip.h | 21 +
src/mainboard/via/epia-m850/devicetree.cb | 62 ++
src/mainboard/via/epia-m850/mainboard.c | 25 +
src/mainboard/via/epia-m850/romstage.c | 77 +++
src/northbridge/amd/amdfam10/.directory | 7 +
src/northbridge/amd/amdmct/mct_ddr3/.directory | 7 +
src/northbridge/via/vx900/Kconfig | 23 +
src/northbridge/via/vx900/Makefile.inc | 33 +
src/northbridge/via/vx900/early_smbus.c | 191 ++++++
src/northbridge/via/vx900/early_vx900.h | 35 +
src/northbridge/via/vx900/forgotten.c | 180 ++++++
src/northbridge/via/vx900/forgotten.h | 78 +++
src/northbridge/via/vx900/raminit.h | 56 ++
src/northbridge/via/vx900/raminit_ddr3.c | 804 ++++++++++++++++++++++++
src/northbridge/via/vx900/romstrap.inc | 50 ++
src/northbridge/via/vx900/romstrap.lds | 27 +
src/northbridge/via/vx900/vx900.h | 26 +
24 files changed, 2460 insertions(+), 0 deletions(-)
diff --git a/src/devices/dram/dram.h b/src/devices/dram/dram.h
new file mode 100644
index 0000000..7543d94
--- /dev/null
+++ b/src/devices/dram/dram.h
@@ -0,0 +1,149 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRAM_H
+#define DRAM_H
+
+#include <stdint.h>
+
+/* DRAM type, byte 2 of spd */
+#define DRAM_TYPE_UNDEFINED 0x00
+#define DRAM_TYPE_FPM_DRAM 0x01
+#define DRAM_TYPE_EDO 0x02
+#define DRAM_TYPE_PIPELINED_NIBBLE 0x03
+#define DRAM_TYPE_SDRAM 0x04
+#define DRAM_TYPE_ROM 0x05
+#define DRAM_TYPE_DDR_SGRAM 0x06
+#define DRAM_TYPE_DDR 0x07
+#define DRAM_TYPE_DDR2 0x08
+#define DRAM_TYPE_DDR2_FBDIMM 0x09
+#define DRAM_TYPE_DDR2_FB_PROBE 0x0a
+#define DRAM_TYPE_DDR3 0x0b
+
+/* Module type (byte 3, bits 3:0) of SPD */
+#define DIMM_TYPE_UNDEFINED 0
+#define DIMM_TYPE_RDIMM 1
+#define DIMM_TYPE_UDIMM 2
+#define DIMM_TYPE_SO_DIMM 3
+#define DIMM_TYPE_MICRO_DIMM 4
+#define DIMM_TYPE_MINI_RDIMM 5
+#define DIMM_TYPE_MINI_UDIMM 6
+#define DIMM_TYPE_MINI_CDIMM 7
+#define DIMM_TYPE_72B_SO_UDIMM 8
+#define DIMM_TYPE_72B_SO_RDIMM 9
+#define DIMM_TYPE_72B_SO_CDIMM 10
+
+#if defined(CONFIG_DEBUG_RAM_SETUP) && (CONFIG_DEBUG_RAM_SETUP)
+#define printram(x, ...) printk(BIOS_DEBUG, x, ##__VA_ARGS__)
+#else
+#define printram(x, ...)
+#endif
+
+/* Different values for tCK, representing standard DDR3 frequencies
+ * As always, these values are in 1/256 ns units */
+#define TCK_1066MHZ 240
+#define TCK_800MHZ 320
+#define TCK_666MHZ 384
+#define TCK_533MHZ 480
+#define TCK_400MHZ 640
+#define TCK_333MHZ 768
+#define TCK_266MHZ 960
+#define TCK_200MHZ 1280
+
+#define RAM_UNIT (1<<24)
+
+#include <stdint.h>
+
+/**
+ *\brief DIMM characteristics
+ *
+ * The characteristics of each DIMM, as presented by the SPD
+ */
+typedef struct dimm_attr_st {
+ u8 dram_type;
+ u16 cas;
+ /* Number of ranks */
+ u8 ranks;
+ /* Number or row address bits */
+ u8 row_bits;
+ /* Number or column address bits */
+ u8 col_bits;
+ /* Size of module in (1 << 24) bytes (16MB) */
+ u16 size;
+ /* Latencies are in units of ns, scaled by x256 */
+ u32 tCK;
+ u32 tAA;
+ u32 tWR;
+ u32 tRCD;
+ u32 tRRD;
+ u32 tRP;
+ u32 tRAS;
+ u32 tRC;
+ u32 tRFC;
+ u32 tWTR;
+ u32 tRTP;
+ u32 tFAW;
+
+} dimm_attr;
+
+typedef struct ramctr_timing_st {
+ u8 dram_type;
+ u16 cas;
+ /* Latencies are in units of ns, scaled by x256 */
+ u32 tCK;
+ u32 tAA;
+ u32 tWR;
+ u32 tRCD;
+ u32 tRRD;
+ u32 tRP;
+ u32 tRAS;
+ u32 tRC;
+ u32 tRFC;
+ u32 tWTR;
+ u32 tRTP;
+ u32 tFAW;
+
+} ramctr_timing;
+
+
+typedef u8 spd_raw_data[256];
+
+/**
+ * \brief Decode the raw spd data
+ */
+void spd_decode_ddr3(dimm_attr *dimm, spd_raw_data spd_data);
+
+/**
+ * \brief Checks if the DIMM is Registered based on byte[3] of the spd
+ */
+int dimm_is_registered(u8 spd_byte3);
+
+/**
+ * \brief Print the info in dimm
+ */
+void dram_print_spd_ddr3(const dimm_attr *dimm);
+
+/**
+ * \brief Read double word from specified address
+ *
+ * Should be useful when doing an MRS to the DIMM
+ */
+u32 volatile_read(u32 addr);
+
+#endif /* DRAM_H */
diff --git a/src/devices/dram/dram_util.c b/src/devices/dram/dram_util.c
new file mode 100644
index 0000000..ca652ce
--- /dev/null
+++ b/src/devices/dram/dram_util.c
@@ -0,0 +1,297 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dram.h"
+#include <console/console.h>
+#include <device/device.h>
+
+u32 volatile_read(volatile u32 addr)
+{
+ volatile u32 result;
+ result = *(volatile u32*)addr;
+ return result;
+}
+
+int dimm_is_registered(u8 spd_byte3)
+{
+ spd_byte3 &= 0x0f;
+ if( (spd_byte3 == DIMM_TYPE_RDIMM)
+ | (spd_byte3 == DIMM_TYPE_MINI_RDIMM)
+ | (spd_byte3 == DIMM_TYPE_72B_SO_RDIMM) )
+ return 1;
+
+ return 0;
+}
+
+void spd_decode_ddr3(dimm_attr *dimm, spd_raw_data spd)
+{
+ int nCRC, i;
+ u16 crc, spd_crc;
+ u8 * ptr = spd;
+ u8 ftb_divisor;
+ u8 ftb_dividend;
+ u8 capacity_shift, bus_width, sdram_width;
+ u32 mtb; /* medium time base */
+ /* Make sure that the spd dump is indeed from a DDR3 module */
+ if(spd[2] != DRAM_TYPE_DDR3)
+ {
+ printram("Not a DDR3 SPD!\n");
+ dimm->dram_type = DRAM_TYPE_UNDEFINED;
+ return;
+ }
+ dimm->dram_type = DRAM_TYPE_DDR3;
+
+ /* Find the number of bytes covered by CRC */
+ if(spd[0] & 0x80) {
+ nCRC = 117;
+ } else {
+ nCRC =126;
+ }
+
+ /* Compute the CRC */
+ crc = 0;
+ while (--nCRC >= 0) {
+ crc = crc ^ (int)*ptr++ << 8;
+ for (i = 0; i < 8; ++i)
+ if (crc & 0x8000) {
+ crc = crc << 1 ^ 0x1021;
+ } else {
+ crc = crc << 1;
+ }
+ }
+ /* Compare with the CRC in the SPD */
+ spd_crc = (spd[127] << 8) + spd[126];
+ /* Verify the CRC is correct */
+ if(crc != spd_crc)
+ printram("SPD CRC failed!!!");
+
+
+ unsigned int reg, val, param;
+ printram(" Revision: %x \n", spd[1] );
+ printram(" Type : %x \n", spd[2] );
+ printram(" Key : %x \n", spd[3] );
+
+ reg = spd[4];
+ /* Number of memory banks */
+ val = (reg >> 4) & 0x07;
+ if (val > 0x03) printram(" Invalid number of memory banks\n");
+ param = 1 << (val + 3);
+ printram(" Banks : %u \n", param );
+ /* SDRAM capacity */
+ capacity_shift = reg & 0x0f;
+ if (capacity_shift > 0x06) printram(" Invalid module capacity\n");
+ if (capacity_shift < 0x02) {
+ printram(" Capacity: %u Mb\n", 256 << capacity_shift);
+ } else {
+ printram(" Capacity: %u Gb\n", 1 << (capacity_shift - 2));
+ }
+
+ reg = spd[5];
+ /* Row address bits */
+ val = (reg >> 4) & 0x07;
+ if(val > 0x04) printram(" Invalid row address bits\n");
+ dimm->row_bits = val + 12;
+ /* Column address bits */
+ val = reg & 0x07;
+ if(val > 0x03) printram(" Invalid column address bits\n");
+ dimm->col_bits = val + 9;
+
+ /* Module nominal voltage */
+ reg = spd[6];
+ print_debug(" Supported voltages: ");
+ if(reg & (1<<2) ) print_debug("1.2V ");
+ if(reg & (1<<1) ) print_debug("1.35V ");
+ if( !(reg & (1<<0)) ) print_debug("1.5V ");
+ print_debug("\n");
+
+ /* Module organization */
+ reg = spd[7];
+ /* Number of ranks*/
+ val = (reg >> 3) & 0x07;
+ if(val > 3) printram(" Invalid number of ranks\n");
+ dimm->ranks = val + 1;
+ /* SDRAM device width */
+ val = (reg & 0x07);
+ if(val > 3) printram(" Invalid SDRAM width\n");
+ sdram_width = (4 << val);
+ printram(" SDRAM width : %u \n", sdram_width);
+
+ /* Memory bus width */
+ reg = spd[8];
+ /* Bus extension */
+ val = (reg >> 3) & 0x03;
+ if(val > 1) printram(" Invalid bus extension\n");
+ printram(" Bus extension : %u bits\n", val?8:0);
+ /* Bus width */
+ val = reg & 0x07;
+ if(val > 3) printram(" Invalid bus width\n");
+ bus_width = 8 << val;
+ printram(" Bus width : %u \n", bus_width);
+
+ /* We have all the info we need to compute the dimm size */
+ /* Capacity is 256Mbit multiplied by the power of 2 specified in
+ * capacity_shift
+ * The rest is the JEDEC formula */
+ /* I am certain it will fit in 16 bits
+ * Remember, It's in units of 2^24 bytes*/
+ dimm->size = ( (1 << (capacity_shift + (25-24)) ) * bus_width
+ * dimm->ranks ) / sdram_width;
+
+ /* Fine Timebase (FTB) Dividend/Divisor */
+ /* Dividend */
+ ftb_dividend = (spd[9] >> 4) & 0x0f;
+ /* Divisor */
+ ftb_divisor = spd[9] & 0x0f;
+
+ /* Medium Timebase =
+ * Medium Timebase (MTB) Dividend /
+ * Medium Timebase (MTB) Divisor */
+ mtb = (((u32)spd[10]) << 8) / spd [11];
+
+ /* SDRAM Minimum Cycle Time (tCKmin) */
+ dimm->tCK = spd[12] * mtb;
+
+ /* CAS Latencies Supported */
+ dimm->cas = (spd[15] << 8) + spd[14];
+
+ /* Minimum CAS Latency Time (tAAmin) */
+ dimm->tAA = spd[16] * mtb;
+
+ /* Minimum Write Recovery Time (tWRmin) */
+ dimm->tWR = spd[17] * mtb;
+
+ /* Minimum RAS# to CAS# Delay Time (tRCDmin) */
+ dimm->tRCD = spd[18] * mtb;
+
+ /* Minimum Row Active to Row Active Delay Time (tRRDmin) */
+ dimm->tRRD = spd[19] * mtb;
+
+ /* Minimum Row Precharge Delay Time (tRPmin)*/
+ dimm->tRP = spd[20] * mtb;
+
+ /* Minimum Active to Precharge Delay Time (tRASmin) */
+ dimm->tRAS = (((spd[21] & 0x0f) << 8) + spd[22]) * mtb;
+
+ /* Minimum Active to Active/Refresh Delay Time (tRCmin) */
+ dimm->tRC = (((spd[21] & 0xf0) << 4) + spd[23]) * mtb;
+
+ /* Minimum Refresh Recovery Delay Time (tRFCmin) */
+ dimm->tRFC = ((spd[25] << 8) + spd[24]) * mtb;
+
+ /* Minimum Internal Write to Read Command Delay Time (tWTRmin) */
+ dimm->tWTR = spd[26] * mtb;
+
+ /* Minimum Internal Read to Precharge Command Delay Time (tRTPmin) */
+ dimm->tRTP = spd[27] * mtb;
+
+ /* Minimum Four Activate Window Delay Time (tFAWmin) */
+ dimm->tFAW = (((spd[28] & 0x0f) << 8) + spd[29]) * mtb;
+
+ /* SDRAM Optional Features */
+ reg = spd[30];
+ print_debug(" Optional features :");
+ if(reg & 0x80) print_debug(" DLL-Off_mode");
+ if(reg & 0x02) print_debug(" RZQ/7");
+ if(reg & 0x01) print_debug(" RZQ/6");
+ print_debug("\n");
+
+ /* SDRAM Thermal and Refresh Options */
+ reg = spd[31];
+ print_debug(" Thermal features :");
+ if(reg & 0x80) print_debug(" PASR");
+ if(reg & 0x08) print_debug(" ODTS");
+ if(reg & 0x04) print_debug(" ASR");
+ if(reg & 0x02) print_debug(" ext_temp_refresh");
+ if(reg & 0x01) print_debug(" ext_temp_range");
+ print_debug("\n");
+
+ /* Module Thermal Sensor */
+ reg = spd[32];
+ print_debug(" Thermal sensor : ");
+ if(reg & 0x80) print_debug("yes");
+ else print_debug("no");
+ print_debug("\n");
+
+ /* SDRAM Device Type */
+ reg = spd[33];
+ print_debug(" Standard SDRAM : ");
+ if(reg & 0x80) print_debug("no");
+ else print_debug("yes");
+ print_debug("\n");
+
+ /* Fine Offset for SDRAM Minimum Cycle Time (tCKmin) */
+ //printram(" tCKmin FTB : %i \n", spd[34]);
+ /* Fine Offset for Minimum CAS Latency Time (tAAmin) */
+ //printram(" tAAmin FTB : %i \n", spd[35]);
+ /* Fine Offset for Minimum RAS# to CAS# Delay Time (tRCDmin) */
+ //printram(" tRCDmin FTB : %i \n", spd[36]);
+ /* Fine Offset for Minimum Row Precharge Delay Time (tRPmin) */
+ //printram(" tRPmin FTB : %i \n", spd[37]);
+ /* Fine Offset for Minimum Active to Active/Refresh Delay Time (tRCmin) */
+ //printram(" tRCmin FTB : %i \n", spd[38]);
+
+ if(spd[60] & 0x01)
+ printram(" DIMM Address bits mirrorred!!!\n");
+
+}
+
+static void print_ns(const char * msg, u32 val)
+{
+ u32 mant, fp;
+ mant = val/256;
+ fp = (val % 256) * 1000/256;
+
+ printram("%s%3u.%.3u ns\n", msg, mant, fp);
+}
+
+void dram_print_spd_ddr3(const dimm_attr *dimm)
+{
+ u16 val16;
+ int i;
+
+ printram(" Row addr bits : %u \n", dimm->row_bits);
+ printram(" Column addr bits : %u \n", dimm->col_bits);
+ printram(" Number of ranks : %u \n", dimm->ranks);
+ printram(" DIMM Capacity : %u MB\n", dimm->size << 4);
+
+ /* CAS Latencies Supported */
+ val16 = dimm->cas;
+ print_debug(" CAS latencies :");
+ i = 0;
+ do{
+ if(val16 & 1) printram(" %u", i + 4);
+ i++;
+ val16 >>= 1;
+ } while(val16);
+ print_debug("\n");
+
+ print_ns(" tCKmin : ", dimm->tCK);
+ print_ns(" tAAmin : ", dimm->tAA);
+ print_ns(" tWRmin : ", dimm->tWR);
+ print_ns(" tRCDmin : ", dimm->tRCD);
+ print_ns(" tRRDmin : ", dimm->tRRD);
+ print_ns(" tRPmin : ", dimm->tRP);
+ print_ns(" tRASmin : ", dimm->tRAS);
+ print_ns(" tRCmin : ", dimm->tRC);
+ print_ns(" tRFCmin : ", dimm->tRFC);
+ print_ns(" tWTRmin : ", dimm->tWTR);
+ print_ns(" tRTPmin : ", dimm->tRTP);
+ print_ns(" tFAWmin : ", dimm->tFAW);
+
+}
diff --git a/src/devices/smbus/early_smbus.c b/src/devices/smbus/early_smbus.c
new file mode 100644
index 0000000..4583aca
--- /dev/null
+++ b/src/devices/smbus/early_smbus.c
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * @file post_codes.h
+ *
+ * This file defines the implementations for the functions defined in smbus.h
+ * These are a generic SMBUS implementation, which should work with a majority
+ * of chipsets.
+ * They are marked weak so that they can be overridden by the chipset code if
+ * necessary.
+ */
+
+#include "smbus.h"
+
+/**
+ * \brief Brief delay for SMBUS transactions
+ */
+__attribute__((weak))
+void __smbus_delay(void)
+{
+ inb(0x80);
+}
+
+/**
+ * \brief Clear the SMBUS host status register
+ */
+__attribute__((weak))
+void __smbus_reset(u16 __smbus_io_base)
+{
+ outb(0xdf, SMBHSTSTAT);
+}
+
+/**
+ * \brief Print an error, should it occur. If no error, just exit.
+ *
+ * @param host_status The data returned on the host status register after
+ * a transaction is processed.
+ * @param loops The number of times a transaction was attempted.
+ * @return 0 if no error occurred
+ * 1 if an error was detected
+ */
+__attribute__((weak))
+int __smbus_print_error(u8 host_status, int loops, u16 __smbus_io_base)
+{
+ /* Check if there actually was an error. */
+ if ((host_status == 0x00 || host_status == 0x40 ||
+ host_status == 0x42) && (loops < SMBUS_TIMEOUT))
+ return 0;
+
+ if (loops >= SMBUS_TIMEOUT)
+ printsmbus("SMBus timeout\n");
+ if (host_status & (1 << 4))
+ printsmbus("Interrupt/SMI# was Failed Bus Transaction\n");
+ if (host_status & (1 << 3))
+ printsmbus("Bus error\n");
+ if (host_status & (1 << 2))
+ printsmbus("Device error\n");
+ if (host_status & (1 << 1))
+ printsmbus("Interrupt/SMI# completed successfully\n");
+ if (host_status & (1 << 0))
+ printsmbus("Host busy\n");
+ return 1;
+}
+
+/**
+ * \brief Checks if the SMBUS is currently busy with a transaction
+ */
+__attribute__((weak))
+int __smbus_is_busy(u16 __smbus_io_base)
+{
+ /* Check if bit 0 of the status register is 1 (busy) or 0 (ready) */
+ return ( (inb(SMBHSTSTAT) & (1 << 0)) == 1);
+}
+
+/**
+ * \brief Wait for the SMBUS to become ready to process a new transaction.
+ */
+__attribute__((weak))
+int __smbus_wait_until_ready(u16 __smbus_io_base)
+{
+ int loops;
+
+ printsmbus("Waiting until SMBus ready\n");
+
+ /* Loop up to SMBUS_TIMEOUT times, waiting for bit 0 of the
+ * SMBus Host Status register to go to 0, indicating the operation
+ * was completed successfully. I don't remember why I did it this way,
+ * but I think it was because ROMCC was running low on registers */
+ loops = 0;
+ while (__smbus_is_busy(__smbus_io_base) && loops < SMBUS_TIMEOUT)
+ ++loops;
+
+ return __smbus_print_error(inb(SMBHSTSTAT), loops, __smbus_io_base);
+}
+
+/**
+ * \brief Read a byte from the SMBUS.
+ *
+ * @param dimm The address location of the DIMM on the SMBus.
+ * @param offset The offset the data is located at.
+ */
+__attribute__((weak))
+u8 __smbus_read_byte(u8 dimm, u8 offset, u16 __smbus_io_base)
+{
+ u8 val;
+
+ /* Initialize SMBUS sequence */
+ __smbus_reset(__smbus_io_base);
+ /* Clear host data port. */
+ outb(0x00, SMBHSTDAT0);
+
+ __smbus_wait_until_ready(__smbus_io_base);
+
+ /* Actual addr to reg format. */
+ dimm = (dimm << 1);
+ dimm |= 1; /* read command */
+ outb(dimm, SMBXMITADD);
+ outb(offset, SMBHSTCMD);
+ /* Start transaction, byte data read. */
+ outb(0x48, SMBHSTCTL);
+ __smbus_wait_until_ready(__smbus_io_base);
+
+ val = inb(SMBHSTDAT0);
+ return val;
+}
\ No newline at end of file
diff --git a/src/devices/smbus/smbus.h b/src/devices/smbus/smbus.h
new file mode 100644
index 0000000..820a0dd
--- /dev/null
+++ b/src/devices/smbus/smbus.h
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file post_codes.h
+ *
+ * This file defines the prototypes for several common SMBUS functions
+ * These functions are prefixed with __smbus_ so that they do not conflict with
+ * the dozens of similar (duplicated) implementations in many southbridges.
+ *
+ * As a last parameter, the SMBUS functions take a u16 value __smbus_io_base,
+ * which represents the base IO port for smbus transactions
+ */
+
+#include <arch/io.h>
+
+/**
+ * \brief SMBUS IO ports in relation to the base IO port
+ */
+#define SMBHSTSTAT __smbus_io_base + 0x0
+#define SMBSLVSTAT __smbus_io_base + 0x1
+#define SMBHSTCTL __smbus_io_base + 0x2
+#define SMBHSTCMD __smbus_io_base + 0x3
+#define SMBXMITADD __smbus_io_base + 0x4
+#define SMBHSTDAT0 __smbus_io_base + 0x5
+#define SMBHSTDAT1 __smbus_io_base + 0x6
+#define SMBBLKDAT __smbus_io_base + 0x7
+#define SMBSLVCTL __smbus_io_base + 0x8
+#define SMBTRNSADD __smbus_io_base + 0x9
+#define SMBSLVDATA __smbus_io_base + 0xa
+
+#define SMBUS_TIMEOUT (100*1000*10)
+
+/**
+ * \brief printk macro for SMBUS debugging
+ */
+#if defined(CONFIG_DEBUG_SMBUS_SETUP) && (CONFIG_DEBUG_SMBUS_SETUP)
+#define printsmbus(x, ...) printk(BIOS_DEBUG, x, ##__VA_ARGS__)
+#else
+#define printsmbus(x, ...)
+#endif
+
+void __smbus_reset(u16 __smbus_io_base);
+int __smbus_print_error(u8 host_status, int loops, u16 __smbus_io_base);
+int __smbus_is_busy(u16 __smbus_io_base);
+int __smbus_wait_until_ready(u16 __smbus_io_base);
+u8 __smbus_read_byte(u8 dimm, u8 offset, u16 __smbus_io_base);
+
+void __smbus_delay(void);
+
+#if defined(SMBUS_IO_BASE) && (SMBUS_IO_BASE != 0)
+
+__attribute__((always_inline, unused))
+static void smbus_reset(void)
+{
+ __smbus_reset(SMBUS_IO_BASE);
+}
+
+__attribute__((always_inline, unused))
+static int smbus_is_busy(void)
+{
+ return __smbus_is_busy(SMBUS_IO_BASE);
+}
+
+__attribute__((always_inline, unused))
+static int smbus_wait_until_ready(void)
+{
+ return __smbus_wait_until_ready(SMBUS_IO_BASE);
+}
+
+__attribute__((always_inline, unused))
+static int smbus_print_error(u8 host_status, int loops)
+{
+ return __smbus_print_error(host_status, loops, SMBUS_IO_BASE);
+}
+
+__attribute__((always_inline, unused))
+static u8 smbus_read_byte(u8 dimm, u8 offset)
+{
+ return __smbus_read_byte(dimm, offset, SMBUS_IO_BASE);
+}
+
+#endif
\ No newline at end of file
diff --git a/src/mainboard/via/epia-m850/.directory b/src/mainboard/via/epia-m850/.directory
new file mode 100644
index 0000000..8a30135
--- /dev/null
+++ b/src/mainboard/via/epia-m850/.directory
@@ -0,0 +1,4 @@
+[Dolphin]
+ShowPreview=true
+Timestamp=2011,8,1,4,33,6
+Version=2
diff --git a/src/mainboard/via/epia-m850/Kconfig b/src/mainboard/via/epia-m850/Kconfig
new file mode 100644
index 0000000..ae46646
--- /dev/null
+++ b/src/mainboard/via/epia-m850/Kconfig
@@ -0,0 +1,47 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+##
+
+if BOARD_VIA_EPIA_M850
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+ def_bool y
+ select ARCH_X86
+ select CPU_VIA_C7
+ select NORTHBRIDGE_VIA_VX900
+ select SUPERIO_FINTEK_F81865F
+ #select BOARD_HAS_FADT
+ #select HAVE_PIRQ_TABLE
+ #select HAVE_ACPI_TABLES
+ #select HAVE_OPTION_TABLE
+ select BOARD_ROMSIZE_KB_512
+ #select RAMINIT_SYSINFO
+
+config MAINBOARD_DIR
+ string
+ default via/epia-m850
+
+config MAINBOARD_PART_NUMBER
+ string
+ default "EPIA-M850"
+
+config IRQ_SLOT_COUNT
+ int
+ default 13
+
+endif # BOARD_VIA_EPIA_M850
diff --git a/src/mainboard/via/epia-m850/Makefile.inc b/src/mainboard/via/epia-m850/Makefile.inc
new file mode 100644
index 0000000..9dffc79
--- /dev/null
+++ b/src/mainboard/via/epia-m850/Makefile.inc
@@ -0,0 +1,21 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+#romstage-y += ./../../../superio/fintek/f81865f/f81865f_early_serial.c
+
diff --git a/src/mainboard/via/epia-m850/chip.h b/src/mainboard/via/epia-m850/chip.h
new file mode 100644
index 0000000..2ac4f12
--- /dev/null
+++ b/src/mainboard/via/epia-m850/chip.h
@@ -0,0 +1,21 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+extern struct chip_operations mainboard_ops;
+
+struct mainboard_config {};
diff --git a/src/mainboard/via/epia-m850/devicetree.cb b/src/mainboard/via/epia-m850/devicetree.cb
new file mode 100644
index 0000000..34f2848
--- /dev/null
+++ b/src/mainboard/via/epia-m850/devicetree.cb
@@ -0,0 +1,62 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+chip northbridge/via/vx900 # Northbridge
+ device lapic_cluster 0 on # APIC cluster
+ chip cpu/via/model_c7 # CPU ATOM (same as VIA C7)
+ device lapic 0 on end # APIC
+ end
+ end
+ device pci_domain 0 on
+ device pci 0.0 on end # AGP Bridge
+ device pci 0.1 on end # Error Reporting
+ device pci 0.2 on end # Host Bus Control
+ device pci 0.3 on end # Memory Controller
+ device pci 0.4 on end # Power Management
+ device pci 0.5 on end # Power Management
+ device pci 0.6 on end # Power Management
+ device pci 0.7 on end # V-Link Controller
+ device pci 1.0 on end # PCI Bridge
+ device pci 1.1 on end # Audio
+ device pci 3.0 on end # PCIE control
+ device pci 3.1 on end # PEX1
+ device pci 3.2 on end # PEX2
+ device pci 3.3 on end # PEX3
+ device pci 3.4 on end # PEX4
+ device pci f.0 on end # IDE/SATA
+ device pci 10.0 on end # USB 1.1
+ device pci 10.1 on end # USB 1.1
+ device pci 10.2 on end # USB 1.1
+ device pci 10.3 on end # USB 1.1
+ device pci 10.4 on end # USB 2.0
+ device pci 11.0 on end # LPC
+ chip drivers/generic/generic # DIMM 0-0-0
+ device i2c 50 on end
+ end
+ chip drivers/generic/generic # DIMM 0-0-1
+ device i2c 51 on end
+ end
+ chip superio/fintek/f81865f # Super duper IO
+ end
+ device pci 11.7 on end # NB/SB control
+ device pci 13.0 on end # PCI Bridge
+ device pci 14.0 on end # HD Audio
+ end
+
+end
diff --git a/src/mainboard/via/epia-m850/mainboard.c b/src/mainboard/via/epia-m850/mainboard.c
new file mode 100644
index 0000000..572f7da
--- /dev/null
+++ b/src/mainboard/via/epia-m850/mainboard.c
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <device/device.h>
+#include "chip.h"
+
+struct chip_operations mainboard_ops = {
+ CHIP_NAME("VIA EPIA-M850 Mainboard")
+};
diff --git a/src/mainboard/via/epia-m850/romstage.c b/src/mainboard/via/epia-m850/romstage.c
new file mode 100644
index 0000000..f458554
--- /dev/null
+++ b/src/mainboard/via/epia-m850/romstage.c
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Inspired from the EPIA-M700
+ */
+
+#include <stdint.h>
+#include <device/pci_def.h>
+#include <device/pci_ids.h>
+#include <arch/io.h>
+#include <device/pnp_def.h>
+#include <arch/romcc_io.h>
+#include <arch/hlt.h>
+#include <console/console.h>
+#include <lib.h>
+#include "cpu/x86/bist.h"
+#include <string.h>
+
+#include "northbridge/via/vx900/early_vx900.h"
+#include "northbridge/via/vx900/raminit.h"
+#include "superio/fintek/f81865f/f81865f_early_serial.c"
+
+#define SERIAL_DEV PNP_DEV(0x2e, 0)
+
+/* cache_as_ram.inc jumps to here. */
+void main(unsigned long bist)
+{
+ /* Enable multifunction bit for northbridge.
+ * This enables the PCI configuration spaces of D0F1 to D0F7 to be
+ * accessed */
+ pci_write_config8(PCI_DEV(0, 0, 0), 0x4f, 0x01);
+
+ f81865f_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE);
+ console_init();
+ print_debug("Console initialized. \n");
+
+ /* Halt if there was a built-in self test failure. */
+ report_bist_failure(bist);
+
+ /* x86 cold boot I/O cmd. */
+ enable_smbus();
+
+ /* If this works, then SMBUS is up and running */
+ //dump_spd_data();
+
+ /* Now we can worry about raminit.
+ * This board only has DDR3, so no need to worry about which DRAM type
+ * to use */
+ dimm_layout dimms = {{0x50, 0x51, SPD_END_LIST}};
+ vx900_init_dram_ddr3(&dimms);
+ //ram_check(0, 640 * 1024);
+ //ram_check(1<<26, (1<<26) + 0x20);
+ ram_check(0x04321000, 0x04321000 + 0x80);
+ ram_check(0, 0x80);
+
+ print_debug("We passed RAM verify\n");
+
+ return;
+
+}
diff --git a/src/northbridge/amd/amdfam10/.directory b/src/northbridge/amd/amdfam10/.directory
new file mode 100644
index 0000000..24fd569
--- /dev/null
+++ b/src/northbridge/amd/amdfam10/.directory
@@ -0,0 +1,7 @@
+[Dolphin]
+ShowPreview=true
+SortOrder=1
+Sorting=1
+Timestamp=2011,8,2,17,56,9
+Version=2
+ViewMode=1
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/.directory b/src/northbridge/amd/amdmct/mct_ddr3/.directory
new file mode 100644
index 0000000..601cad6
--- /dev/null
+++ b/src/northbridge/amd/amdmct/mct_ddr3/.directory
@@ -0,0 +1,7 @@
+[Dolphin]
+ShowPreview=true
+SortOrder=1
+Sorting=1
+Timestamp=2011,8,2,17,57,51
+Version=2
+ViewMode=1
diff --git a/src/northbridge/via/vx900/Kconfig b/src/northbridge/via/vx900/Kconfig
new file mode 100644
index 0000000..60e7993
--- /dev/null
+++ b/src/northbridge/via/vx900/Kconfig
@@ -0,0 +1,23 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+config NORTHBRIDGE_VIA_VX900
+ bool
+ select HAVE_DEBUG_RAM_SETUP
+ select HAVE_DEBUG_SMBUS
\ No newline at end of file
diff --git a/src/northbridge/via/vx900/Makefile.inc b/src/northbridge/via/vx900/Makefile.inc
new file mode 100644
index 0000000..5450b1d
--- /dev/null
+++ b/src/northbridge/via/vx900/Makefile.inc
@@ -0,0 +1,33 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+romstage-y += early_smbus.c
+romstage-y += raminit_ddr3.c
+romstage-y += ./../../../devices/dram/dram_util.c
+romstage-y += ./../../../devices/smbus/early_smbus.c
+
+# Drivers for these devices already exist with the vx800
+# Use those instead of duplicating code
+
+driver-y += ./../vx800/northbridge.c
+driver-y += ./../vx800/vga.c
+driver-y += ./../vx800/lpc.c
+
+chipset_bootblock_inc += $(src)/northbridge/via/vx900/romstrap.inc
+chipset_bootblock_lds += $(src)/northbridge/via/vx900/romstrap.lds
\ No newline at end of file
diff --git a/src/northbridge/via/vx900/early_smbus.c b/src/northbridge/via/vx900/early_smbus.c
new file mode 100644
index 0000000..aa6cec0
--- /dev/null
+++ b/src/northbridge/via/vx900/early_smbus.c
@@ -0,0 +1,191 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <device/pci_ids.h>
+#include "early_vx900.h"
+
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <console/console.h>
+#include <devices/dram/dram.h>
+
+__attribute__((unused))
+static void smbus_delays(int delays)
+{
+ while(delays--) __smbus_delay();
+}
+
+
+/**
+ * Read a byte from the SMBus.
+ *
+ * @param dimm The address location of the DIMM on the SMBus.
+ * @param offset The offset the data is located at.
+ */
+u8 __smbus_read_byte(u8 dimm, u8 offset, u16 __smbus_io_base)
+{
+ u8 val;
+
+ /* Initialize SMBUS sequence */
+ smbus_reset();
+ /* Clear host data port. */
+ outb(0x00, SMBHSTDAT0);
+
+ smbus_wait_until_ready();
+ smbus_delays(50);
+
+ /* Actual addr to reg format. */
+ dimm = (dimm << 1);
+ dimm |= 1; /* read command */
+ outb(dimm, SMBXMITADD);
+ outb(offset, SMBHSTCMD);
+ /* Start transaction, byte data read. */
+ outb(0x48, SMBHSTCTL);
+ smbus_wait_until_ready();
+
+ val = inb(SMBHSTDAT0);
+ return val;
+}
+
+void enable_smbus(void)
+{
+ device_t dev;
+ u8 reg8;
+ u16 __smbus_io_base = SMBUS_IO_BASE;
+
+ /* Locate the Power Management control */
+ dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_VX900_LPC), 0);
+
+ if (dev == PCI_DEV_INVALID) {
+ die("Power Managment Controller not found\n");
+ }
+
+ /*
+ * To use SMBus to manage devices on the system board, it is a must to
+ * enable SMBus function by setting
+ * PMU_RXD2[0] (SMBus Controller Enable) to 1.
+ * And set PMU_RXD0 and PMU_RXD1 (SMBus I/O Base) to an appropriate
+ * I/O port address, so that all registers in SMBus I/O port can be
+ * accessed.
+ */
+
+ reg8 = pci_read_config8(dev, 0xd2);
+ /* Enable SMBus controller */
+ reg8 |= 1;
+ /* Set SMBUS clock from 128k source */
+ reg8 |= 1<<2;
+ pci_write_config8(dev, 0xd2, reg8);
+
+ reg8 = pci_read_config8(dev, 0x94);
+ /* SMBUS clock from divider of 14.318 MHz */
+ reg8 &= ~(1<<7);
+ pci_write_config8(dev, 0x94, reg8);
+
+ /* Set SMBus IO base */
+ pci_write_config16(dev, 0xd0, SMBUS_IO_BASE);
+
+ /*
+ * Initialize the SMBus sequence:
+ */
+ /* Clear SMBus host status register */
+ smbus_reset();
+ /* Clear SMBus host data 0 register */
+ outb(0x00, SMBHSTDAT0);
+
+ /* Wait for SMBUS */
+ smbus_wait_until_ready();
+
+}
+
+void spd_read(u8 addr, spd_raw_data spd)
+{
+ u8 reg;
+ int i, regs;
+ reg = smbus_read_byte(addr, 2);
+ if(reg != 0x0b)
+ {
+ printk(BIOS_DEBUG, "SMBUS device %x not a DDR3 module\n", addr);
+ spd[2] = 0;
+ return;
+ }
+
+ reg = smbus_read_byte(addr, 0);
+ reg &= 0xf;
+ if (reg == 0x3) {
+ regs = 256;
+ } else if (reg == 0x2) {
+ regs = 176;
+ } else if (reg == 0x1) {
+ regs = 128;
+ } else {
+ printk(BIOS_INFO, "No DIMM present at %x\n", addr);
+ spd[2] = 0;
+ return;
+ }
+ printk(BIOS_DEBUG, "SPD Data for DIMM %x \n", addr);
+ for (i = 0; i < regs; i++) {
+ reg = smbus_read_byte(addr, i);
+ //printk(BIOS_DEBUG, " Offset %u = 0x%x \n", i, reg );
+ spd[i] = reg;
+ }
+}
+
+void dump_spd_data(void)
+{
+ int dimm, offset, regs;
+ unsigned int reg;
+ spd_raw_data spd;
+ dimm_attr dimmx;
+
+ for (dimm = 0x50; dimm < 0x52; dimm++) {
+ reg = smbus_read_byte(dimm, 2);
+ if(reg != 0x0b)
+ {
+ printk(BIOS_DEBUG,
+ "SMBUS device %x not a DDR3 module\n", dimm);
+ continue;
+ }
+
+ reg = smbus_read_byte(dimm, 0);
+ reg &= 0xf;
+ if (reg == 0x3) {
+ regs = 256;
+ } else if (reg == 0x2) {
+ regs = 176;
+ } else if (reg == 0x1) {
+ regs = 128;
+ } else {
+ printk(BIOS_INFO, "No DIMM present at %x\n", dimm);
+ regs = 0;
+ continue;
+ }
+ printk(BIOS_DEBUG, "SPD Data for DIMM %x \n", dimm);
+ for (offset = 0; offset < regs; offset++) {
+ reg = smbus_read_byte(dimm, offset);
+ //printk(BIOS_DEBUG, " Offset %u = 0x%x \n", offset, reg );
+ spd[offset] = reg;
+ }
+
+ spd_decode_ddr3(&dimmx, spd);
+ dram_print_spd_ddr3(&dimmx);
+
+ }
+}
+
diff --git a/src/northbridge/via/vx900/early_vx900.h b/src/northbridge/via/vx900/early_vx900.h
new file mode 100644
index 0000000..6b33077
--- /dev/null
+++ b/src/northbridge/via/vx900/early_vx900.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EARLY_VX900_H
+#define EARLY_VX900_H
+
+#include <stdint.h>
+
+#define SMBUS_IO_BASE 0x500
+#include <devices/smbus/smbus.h>
+
+
+#include "raminit.h"
+
+void enable_smbus(void);
+void dump_spd_data(void);
+void spd_read(u8 addr, spd_raw_data spd);
+
+#endif /* EARLY_VX900_H */
diff --git a/src/northbridge/via/vx900/forgotten.c b/src/northbridge/via/vx900/forgotten.c
new file mode 100644
index 0000000..c3d3ed8
--- /dev/null
+++ b/src/northbridge/via/vx900/forgotten.c
@@ -0,0 +1,180 @@
+#include "forgotten.h"
+
+u16 ddr3_get_mr0(
+ char precharge_pd,
+ u8 write_recovery,
+ char dll_reset,
+ char mode,
+ u8 cas,
+ char interleaved_burst,
+ u8 burst_lenght
+){
+ u32 cmd = 0;
+ if(precharge_pd) cmd |= (1 << 12);
+ /* Write recovery */
+ cmd |= ( ((write_recovery - 4) & 0x7) << 9);
+ if(dll_reset) cmd |= (1 << 8);
+ if(mode) cmd |= (1<<7);
+ /* CAS latency) */
+ cmd |= ( ((cas - 4) & 0x7) << 4);
+ if(interleaved_burst) cmd |= (1 << 3);
+ /* Burst lenght */
+ cmd |= (burst_lenght & 0x3);
+ return cmd;
+}
+
+u16 ddr3_get_mr1(
+ char q_off_disable,
+ char tdqs,
+ u8 rtt_nom,
+ char write_leveling,
+ u8 output_drive_strenght,
+ u8 additive_latency,
+ u8 dll_disable
+){
+ u32 cmd = 0;
+ if(q_off_disable) cmd |= (1 << 12);
+ if(tdqs) cmd |= (1 << 11);
+ /* rtt_nom */
+ cmd |= ( ((rtt_nom & 4) << 9) | ((rtt_nom & 2) << 6)
+ | ((rtt_nom & 1) << 2));
+ if(write_leveling) cmd |= (1 << 7);
+ /* output drive strenght */
+ cmd |= ( ((output_drive_strenght & 2) << 5)
+ | ((output_drive_strenght & 1) << 1) );
+ /* Additive latency */
+ cmd |= ((additive_latency & 0x3) << 3);
+ if(dll_disable) cmd |= (1 << 0);
+ return cmd;
+}
+
+u16 ddr3_get_mr2(
+ u8 rtt_wr,
+ char extended_temp,
+ char auto_self_refresh,
+ u8 cas_write
+){
+ u32 cmd = 0;
+ /* Rtt_wr */
+ cmd |= ( (rtt_wr & 0x3) << 9);
+ if(extended_temp) cmd |= (1 << 7);
+ if(auto_self_refresh) cmd |= (1 << 6);
+ /* CAS write latency */
+ cmd |= ( ((cas_write - 5) & 0x7) << 3);
+ return cmd;
+}
+
+u16 ddr3_get_mr3(char dataflow_from_mpr)
+{
+ u32 cmd = 0;
+ if(dataflow_from_mpr) cmd |= (1<<2);
+ return cmd;
+}
+
+/*
+ * Translate the MRS command into the memory address corresponding to the
+ * command. This is based on the CPU address to memory address mapping described
+ * by the initial values of registers 0x52 and 0x53, so do not fuck with them
+ * until after the MRS commands have been sent to all ranks
+ */
+static u32 vx900_get_mrs_addr(u8 mrs_type, u16 cmd)
+{
+ u32 addr = 0;
+ /* A3 <-> MA0, A4 <-> MA1, ... A12 <-> MA9 */
+ addr |= ((cmd &0x3ff)<< 3);
+ /* A20 <-> MA10 */
+ addr |= (((cmd >> 10) & 0x1) << 20);
+ /* A13 <-> MA11, A14 <-> MA12 */
+ addr |= (((cmd >> 11) & 0x3) << 13);
+
+ /* Do not fuck with registers 0x52 and 0x53 if you want the following
+ * mappings to work for you:
+ * A17 <-> BA0, A18 <-> BA1, A19 <-> BA2 */
+ addr |= ((mrs_type & 0x7) << 17);
+ return addr;
+}
+void vx900_dram_ddr3_init_rank(device_t mcu, int rank);
+void vx900_dram_ddr3_init_rank(device_t mcu, int rank)
+{
+ u8 reg8;
+ u16 reg16;
+ u32 reg32, cmd, res, addr;
+
+ printram("Initializing rank %u\n", rank);
+
+ reg16 = 0xbbbb;
+ reg16 &= ~(0xf << (4 * rank));
+ reg16 |= (0x8 << (4 * rank));
+ pci_write_config16(mcu, 0x54, reg16);
+
+ /* Step 06 - Set Fun3_RX6B[2:0] to 001b (NOP Command Enable). */
+ reg8 = pci_read_config8(mcu, 0x6b);
+ reg8 &= ~(0x03);
+ reg8 |= (1<<0);
+ pci_write_config8(mcu, 0x6b, reg8);
+ /* Step 07 - Read a double word from any address of the DIMM. */
+ reg32 = volatile_read(0x0);
+ printram("We just read 0x%x\n", reg32);
+ /* Step 08 - Set Fun3_RX6B[2:0] to 011b (MSR Enable). */
+ reg8 = pci_read_config8(mcu, 0x6b);
+ reg8 &= ~(0x03);
+ reg8 |= (3<<0);
+ pci_write_config8(mcu, 0x6b, reg8);
+
+ /* Step 09 – Issue MR2 cycle. Read a double word from the address depended
+ * on DRAM’s Rtt_WR and CWL settings.
+ * (Check the byte 63 of SPD. If memory address lines of target physical
+ * rank is mirrored, MA3~MA8 and BA0~BA1 should be swapped.) */
+ cmd = ddr3_get_mr2(2,0,0,7);
+ addr = vx900_get_mrs_addr(2, cmd);
+ res = volatile_read(addr);
+ printram("MR2 cycle 0x%.4x @ addr 0x%.8x read 0x%.8x\n", cmd, addr, res);
+
+ /* Step 10 – Issue MR3 cycle. Read a double word from the address 60000h to
+ * set DRAM to normal operation mode.
+ * (Check the byte 63 of SPD. If memory address lines of target physical
+ * rank is mirrored, MA3~MA8 and BA0~BA1 should be swapped.) */
+ cmd = ddr3_get_mr3(0);
+ addr = vx900_get_mrs_addr(3, cmd);
+ res = volatile_read(addr);
+ printram("MR3 cycle 0x%.4x @ addr 0x%.8x read 0x%.8x\n", cmd, addr, res);
+
+ /* Step 11 –Issue MR1 cycle. Read a double word from the address depended
+ * on DRAM’s output driver impedance and Rtt_Nom settings.
+ * The DLL enable field, TDQS field, write leveling enable field,
+ * additive latency field, and Qoff field should be set to 0.
+ * (Check the byte 63 of SPD. If memory address lines of target physical
+ * rank is mirrored, MA3~MA8 and BA0~BA1 should be swapped.) */
+ cmd = ddr3_get_mr1(DDR3_MR1_QOFF_ENABLE, DDR3_MR1_TQDS_DISABLE, 3,
+ DDR3_MR1_WRITE_LEVELING_DISABLE, 1,
+ DDR3_MR1_AL_DISABLE, DDR3_MR1_DLL_ENABLE);
+ addr = vx900_get_mrs_addr(1, cmd);
+ res = volatile_read(addr);
+ printram("MR1 cycle 0x%.4x @ addr 0x%.8x read 0x%.8x\n", cmd, addr, res);
+
+ /* Step 12 - Issue MR0 cycle. Read a double word from the address depended
+ * on DRAM’s burst length, CAS latency and write recovery time settings.
+ * The read burst type field should be set to interleave.
+ * The mode field should be set to normal mode.
+ * The DLL reset field should be set to No.
+ * The DLL control for precharge PD field should be set to Fast exit.
+ * (Check the byte 63 of SPD. If memory address lines of target
+ * physical rank is mirrored, MA3~MA8 and BA0~BA1 should be swapped.) */
+ cmd = ddr3_get_mr0(DDR3_MR0_PRECHARGE_FAST, 7, DDR3_MR0_MODE_NORMAL,
+ DDR3_MR0_DLL_RESET_NO, 7,
+ DDR3_MR0_BURST_TYPE_INTERLEAVED,
+ 1);
+ addr = vx900_get_mrs_addr(0, cmd);
+ res = volatile_read(addr);
+ printram("MR0 cycle 0x%.4x @ addr 0x%.8x read 0x%.8x\n", cmd, addr, res);
+
+ /* Step 13 - Set Fun3_RX6B[2:0] to 110b (Long ZQ calibration command). */
+ reg8 = pci_read_config8(mcu, 0x6b);
+ reg8 &= ~(0x03);
+ reg8 |= (3<<1);
+ pci_write_config8(mcu, 0x6b, reg8);
+
+ /* Step 14 - Read a double word from any address of the DIMM. */
+ reg32 = volatile_read(0x0);
+ printram("We just read 0x%x\n", reg32);
+}
\ No newline at end of file
diff --git a/src/northbridge/via/vx900/forgotten.h b/src/northbridge/via/vx900/forgotten.h
new file mode 100644
index 0000000..43641f7
--- /dev/null
+++ b/src/northbridge/via/vx900/forgotten.h
@@ -0,0 +1,78 @@
+#ifndef REDUNDANT_H
+#define REDUNDANT_H
+
+#define DDR3_MR0_PRECHARGE_SLOW 0
+#define DDR3_MR0_PRECHARGE_FAST 1
+#define DDR3_MR0_MODE_NORMAL 0
+#define DDR3_MR0_MODE_TEST 1
+#define DDR3_MR0_DLL_RESET_NO 0
+#define DDR3_MR0_DLL_RESET_YES 1
+#define DDR3_MR0_BURST_TYPE_SEQUENTIAL 0
+#define DDR3_MR0_BURST_TYPE_INTERLEAVED 1
+#define DDR3_MR0_BURST_LENGTH_FIXED_8 0
+#define DDR3_MR0_BURST_LENGTH_CHOP 1
+#define DDR3_MR0_BURST_LENGTH_FIXED_4 2
+/**
+ * \brief Get command address for a DDR3 MR0 command
+ */
+u16 ddr3_get_mr0(
+ char precharge_pd,
+ u8 write_recovery,
+ char dll_reset,
+ char mode,
+ u8 cas,
+ char interleaved_burst,
+ u8 burst_lenght
+);
+
+#define DDR3_MR1_TQDS_DISABLE 0
+#define DDR3_MR1_TQDS_ENABLE 1
+#define DDR3_MR1_QOFF_ENABLE 0
+#define DDR3_MR1_QOFF_DISABLE 1
+#define DDR3_MR1_WRITE_LEVELING_DISABLE 0
+#define DDR3_MR1_WRITE_LEVELING_ENABLE 1
+#define DDR3_MR1_RTT_NOM_OFF 0
+#define DDR3_MR1_RTT_NOM_RZQ4 1
+#define DDR3_MR1_RTT_NOM_RZQ2 2
+#define DDR3_MR1_RTT_NOM_RZQ6 3
+#define DDR3_MR1_RTT_NOM_RZQ12 4
+#define DDR3_MR1_RTT_NOM_RZQ8 5
+#define DDR3_MR1_AL_DISABLE 0
+#define DDR3_MR1_AL_CL_MINUS_1 1
+#define DDR3_MR1_AL_CL_MINUS_2 2
+#define DDR3_MR1_ODS_RZQ6 0
+#define DDR3_MR1_ODS_RZQ7 1
+#define DDR3_MR1_DLL_ENABLE 0
+#define DDR3_MR1_DLL_DISABLE 1
+/**
+ * \brief Get command address for a DDR3 MR1 command
+ */
+u16 ddr3_get_mr1(
+ char q_off,
+ char tdqs,
+ u8 rtt_nom,
+ char write_leveling,
+ u8 output_drive_strenght,
+ u8 additive_latency,
+ u8 dll_disable
+);
+
+#define DDR3_MR2_RTT_WR_OFF 0
+#define DDR3_MR2_RTT_WR_RZQ4 1
+#define DDR3_MR2_RTT_WR_RZQ2 2
+/**
+ * \brief Get command address for a DDR3 MR2 command
+ */
+u16 ddr3_get_mr2(
+ u8 rtt_wr,
+ char extended_temp,
+ char auto_self_refresh,
+ u8 cas_write
+);
+
+/**
+ * \brief Get command address for a DDR3 MR3 command
+ */
+u16 ddr3_get_mr3(char dataflow_from_mpr);
+
+#endif /* REDUNDANT_H */
\ No newline at end of file
diff --git a/src/northbridge/via/vx900/raminit.h b/src/northbridge/via/vx900/raminit.h
new file mode 100644
index 0000000..f90cb60
--- /dev/null
+++ b/src/northbridge/via/vx900/raminit.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RAMINIT_VX900_H
+#define RAMINIT_VX900_H
+
+#include <devices/dram/dram.h>
+
+/* The maximum number of DIMM slots that the VX900 supports */
+#define VX900_MAX_DIMM_SLOTS 2
+
+#define VX900_MAX_MEM_RANKS 4
+
+
+#define SPD_END_LIST 0xff
+
+typedef struct dimm_layout_st
+{
+ /* The address of the DIMM on the SMBUS *
+ * 0xFF to terminate the array*/
+ u8 spd_addr[VX900_MAX_DIMM_SLOTS + 1];
+} dimm_layout;
+
+typedef struct dimm_info_st
+{
+ dimm_attr dimm[VX900_MAX_DIMM_SLOTS];
+} dimm_info;
+
+typedef struct mem_rank_st {
+ u16 start_addr;
+ u16 end_addr;
+}mem_rank;
+
+typedef struct rank_layout_st {
+ u32 phys_rank_size[VX900_MAX_MEM_RANKS];
+ mem_rank virt[VX900_MAX_MEM_RANKS];
+} rank_layout;
+void vx900_init_dram_ddr3(const dimm_layout *dimms);
+
+#endif /* RAMINIT_VX900_H */
diff --git a/src/northbridge/via/vx900/raminit_ddr3.c b/src/northbridge/via/vx900/raminit_ddr3.c
new file mode 100644
index 0000000..2b1d9eb
--- /dev/null
+++ b/src/northbridge/via/vx900/raminit_ddr3.c
@@ -0,0 +1,804 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+
+#include "early_vx900.h"
+#include "raminit.h"
+
+#include <string.h>
+#include <console/console.h>
+#include <device/pci_ids.h>
+
+#define min(a,b) a<b?a:b
+#define max(a,b) a>b?a:b
+
+#define MCU PCI_DEV(0, 0, 3)
+
+typedef struct pci_reg8_st {
+ u8 addr;
+ u8 val;
+} pci_reg8;
+
+/* These are some "safe" values that can be used for memory initialization.
+ * Some will stay untouched, and others will be overwritten later on */
+static pci_reg8 mcu_init_config[] = {
+ {0x40, 0x01}, /* Virtual rank 0 ending address = 64M - 1 */
+ {0x48, 0x00}, /* Virtual rank 0 starting address = 0 */
+ {0x50, 0xd8}, /* Set ranks 0-3 to 11 col bits, 16 row bits */
+ {0x52, 0x33}, /* Map BA0 to A15, BA1 to A18 */
+ {0x53, 0x0b}, /* Map BA2 to A19 */
+ /* Disable rank interkeaving in ranks 0-3 */
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x6c, 0xA0}, /* Memory type: DDR3, VDIMM: 1.5V, 64-bit DRAM */
+ {0x6e, 0x38}, /* Burst lenght: 8, burst-chop: enable */
+ {0xc6, 0x80}, /* Minimum latency from self-refresh. Bit [7] must be 1 */
+ {0xc8, 0x80}, /* Enable automatic triggering of short ZQ calibration */
+ /* Enable differential DQS; MODT assertion values suggested in DS */
+ {0x9e, 0xa1}, {0x9f, 0x50}
+};
+
+/* FIXME: DO NOT ACCEPT THIS PATCH IF YOU SEE THIS ARRAY
+ * This is just a cheat sheet to get the config up and running, and is specific
+ * to my hardware setup. */
+static pci_reg8 mcu_cheat_sheet[] = {
+ /* Number of row, col and bank bits */
+ {0x50, 0xa0},
+ /* Rank interleave address select */
+ {0x52, 0x11}, {0x53, 0x59},
+ /* DRAM Pipeline control */
+ {0x60, 0xf4}, {0x61, 0x2e},
+ /* DRAM arbitration */
+ {0x65, 0x49}, {0x66, 0x80},
+ /* Bank interleave control; request reorder control */
+ {0x69, 0xe7}, {0x6a, 0xfc},
+
+ /* very finetuned timing; do not touch; leave commented out */
+ // {0x72, 0x0f}, {0x73, 0x04},
+ // {0x76, 0x68}, {0x77, 0x10},
+
+ /* Top mem; need to calculate this dynamically */
+ {0x84, 0x01}, {0x85, 0x40},
+
+ /* DRAM clocking control; mostly finetuned delays ; leave out */
+ /*{0x91, 0x08}, {0x92, 0x08}, {0x93, 0x16},
+ {0x94, 0x00}, {0x95, 0x16}, {0x96, 0x00}, {0x97, 0xa4},
+ {0x98, 0xba}, {0x99, 0xff}, {0x9a, 0x80},
+ {0x9c, 0xe4},
+ */
+
+};
+/* FIXME: Cheat sheet number two
+ * We need to set driving strength before trying to operate the controller
+ * It's like putting it in first gear before pushing the accelerator */
+static pci_reg8 memdrv_cheat_sheet[] = {
+ /* Enable memory clock output */
+ //{0x9b, 0x3f}, // on by default
+
+ {0xd3, 0x01}, /* Enable controller ODT auto-compensation */
+
+ /* Memory driving controls */
+ /* ?? Internal ODT control ?? */
+ //{0xd4, 0x80},
+ /* ?? ODT Range selection ?? */
+ {0xd5, 0x04},
+ /* ?? MCLK/MA/MCS driving selection ?? */
+ //{0xd6, 0x20},
+ /* Auto compensation mode for _everything_ */
+ {0xe1, 0x7e},
+
+};
+
+static void vx900_dram_write_init_config(void)
+{
+ size_t i;
+ for(i = 0; i < (sizeof(mcu_init_config)/sizeof(pci_reg8)); i++)
+ pci_write_config8(MCU, mcu_init_config[i].addr,
+ mcu_init_config[i].val);
+}
+
+static void dram_find_spds_ddr3(const dimm_layout *addr, dimm_info *dimm)
+{
+ size_t i = 0;
+ int dimms = 0;
+ do {
+ spd_raw_data spd;
+ spd_read(addr->spd_addr[i], spd);
+ spd_decode_ddr3(&dimm->dimm[i], spd);
+ if(dimm->dimm[i].dram_type != DRAM_TYPE_DDR3) continue;
+ dimms++;
+ dram_print_spd_ddr3(&dimm->dimm[i]);
+ } while(addr->spd_addr[++i] != SPD_END_LIST
+ && i < VX900_MAX_DIMM_SLOTS);
+
+ if(!dimms)
+ die("No DIMMs were found");
+}
+
+static void dram_find_common_params(const dimm_info *dimms, ramctr_timing *ctrl)
+{
+ size_t i, valid_dimms;
+ memset(ctrl, 0, sizeof(ramctr_timing));
+ ctrl->cas = 0xff;
+ valid_dimms = 0;
+ for(i = 0; i < VX900_MAX_DIMM_SLOTS; i++)
+ {
+ const dimm_attr *dimm = &dimms->dimm[i];
+ if(dimm->dram_type == DRAM_TYPE_UNDEFINED) continue;
+ valid_dimms++;
+
+ if(valid_dimms == 1) {
+ /* First DIMM defines the type of DIMM */
+ ctrl->dram_type = dimm->dram_type;
+ } else {
+ /* Check if we have mismatched DIMMs */
+ if(ctrl->dram_type != dimm->dram_type)
+ die("Mismatched DIMM Types");
+ }
+ /* Find all possible CAS combinations */
+ ctrl->cas &= dimm->cas;
+
+ /* Find the smallest common latencies supported by all DIMMs */
+ ctrl->tCK = max(ctrl->tCK, dimm->tCK );
+ ctrl->tAA = max(ctrl->tAA, dimm->tAA );
+ ctrl->tWR = max(ctrl->tWR, dimm->tWR );
+ ctrl->tRCD = max(ctrl->tRCD, dimm->tRCD);
+ ctrl->tRRD = max(ctrl->tRRD, dimm->tRRD);
+ ctrl->tRP = max(ctrl->tRP, dimm->tRP );
+ ctrl->tRAS = max(ctrl->tRAS, dimm->tRAS);
+ ctrl->tRC = max(ctrl->tRC, dimm->tRC );
+ ctrl->tRFC = max(ctrl->tRFC, dimm->tRFC);
+ ctrl->tWTR = max(ctrl->tWTR, dimm->tWTR);
+ ctrl->tRTP = max(ctrl->tRTP, dimm->tRTP);
+ ctrl->tFAW = max(ctrl->tFAW, dimm->tFAW);
+
+ }
+
+ if(!ctrl->cas) die("Unsupported DIMM combination. "
+ "DIMMS do not support common CAS latency");
+ if(!valid_dimms) die("No valid DIMMs found");
+}
+
+static void vx900_dram_phys_bank_range(const dimm_info *dimms,
+ rank_layout *ranks)
+{
+ size_t i;
+ u8 reg8;
+ for(i = 0; i < VX900_MAX_DIMM_SLOTS; i ++)
+ {
+ if(dimms->dimm[i].dram_type == DRAM_TYPE_UNDEFINED)
+ continue;
+ u8 nranks = dimms->dimm[i].ranks;
+ if(nranks > 2)
+ die("Found DIMM with more than two ranks, which is not"
+ "supported by this chipset");
+ u32 size = dimms->dimm[i].size;
+ if(nranks == 2) {
+ /* Each rank holds half the capacity of the DIMM */
+ size >>= 1;
+ ranks->phys_rank_size[i<<1] = size;
+ ranks->phys_rank_size[(i<<1) | 1] = size;
+ } else {
+ /* Otherwise, everything is held in the first bank */
+ ranks->phys_rank_size[i<<1] = size;
+ ranks->phys_rank_size[(i<<1) | 1] = 0;;
+ }
+ }
+ /* There's a tiny thing we need to do:
+ * set the column and row address bits
+ * FIXME: Really bad programming here */
+ reg8 = 0;// ((( (1<<2) | (dimms->dimm[0].col_bits - 9) ) & 0x7) << 2);
+ reg8 |= ((( (1<<2) | (dimms->dimm[1].col_bits - 9) ) & 0x7) << 5);
+ pci_write_config8(PCI_DEV(0,0,3), 0x50, reg8);
+
+}
+
+static void vx900_dram_driving_ctrl(void)
+{
+ /* My memory drive strength cheat sheet */
+ size_t i;
+ for(i = 0; i < (sizeof(memdrv_cheat_sheet)/sizeof(pci_reg8)); i++)
+ pci_write_config8(MCU, memdrv_cheat_sheet[i].addr,
+ memdrv_cheat_sheet[i].val);
+}
+
+static void vx900_dram_range(ramctr_timing *ctrl, rank_layout *ranks)
+{
+ size_t i, vrank = 0;
+ u8 reg8;
+ u32 reg32 = 0, ramsize = 0;
+ for(i = 0; i < VX900_MAX_MEM_RANKS; i++)
+ {
+ u32 rank_size = ranks->phys_rank_size[i];
+ if(!rank_size) continue;
+ ranks->virt[vrank].start_addr = ramsize;
+ ramsize += rank_size;
+ ranks->virt[vrank].end_addr = ramsize;
+
+ /* Physical to virtual rank mapping */
+ /* The position of the bit that enables physical rank [i] */
+ const char rank_en_bit[] = {3, 7, 11, 15};
+ /* The position of the LSB of the VR mapping of rank [i] */
+ const char rank_map_pos[] = {0, 4, 8, 12};
+ /* Enable the physical rank */
+ reg32 |= ( 1 << rank_en_bit[i]);
+ /* Map the physical rank to the first unused virtual rank */
+ reg32 |= (vrank << rank_map_pos[i]);
+ /* Rank memory range */
+ reg8 = (ranks->virt[vrank].start_addr >> 2);
+ pci_write_config8(MCU, 0x48 + vrank, reg8);
+ reg8 = (ranks->virt[vrank].end_addr >> 2);
+ pci_write_config8(MCU, 0x40 + vrank, reg8);
+
+ printram("Mapped Physical rank %u, to virtual rank %u\n"
+ " Start address: 0x%.10x000000\n"
+ " End address: 0x%.10x000000\n",
+ (int) i, (int) vrank,
+ ranks->virt[vrank].start_addr,
+ ranks->virt[vrank].end_addr);
+
+ /* Move on to next virtual rank */
+ vrank++;
+ }
+
+ /* Finally, write the mapping configuration to the MCU */
+ pci_write_config32(MCU, 0x54, reg32);
+
+ printram("Initialized %u virtual ranks, with a total size of %u MB\n",
+ (int) vrank, ramsize << 4);
+}
+
+static void vx900_dram_freq_latency(ramctr_timing *ctrl)
+{
+ u8 reg8, val;
+ u32 val32;
+
+ /* Maximum supported DDR3 frequency is 533MHz (DDR3 1066)
+ * so make sure we cap it if we have faster DIMMs */
+ if(ctrl->tCK < TCK_533MHZ) ctrl->tCK = TCK_533MHZ;
+ val32 = (1000 << 8) / ctrl->tCK;
+ printram("Selected DRAM frequency: %u MHz\n", val32);
+
+ /* To change the DRAM frequency, it is required to set this bits to
+ * 1111b to reset the PLL first and set to the target value then.
+ * Minimum assertion time for the PLL Reset is 10 ns.
+ * Datasheet also states that the DRAM frequency must be set first */
+ /* Reset the PLL */
+ pci_write_config8(MCU, 0x90, 0x0f);
+ /* Wait at least 10 ns; in this case, we will wait about 1 us */
+ inb(0x80);
+ /* Now find the right DRAM frequency setting,
+ * and bring it to the closest JEDEC standard frequency */
+ if(ctrl->tCK <= TCK_533MHZ) {val = 0x07; ctrl->tCK = TCK_533MHZ;}
+ else if(ctrl->tCK <= TCK_400MHZ) {val = 0x06; ctrl->tCK = TCK_400MHZ;}
+ else if(ctrl->tCK <= TCK_333MHZ) {val = 0x05; ctrl->tCK = TCK_333MHZ;}
+ else if(ctrl->tCK <= TCK_266MHZ) {val = 0x04; ctrl->tCK = TCK_266MHZ;}
+
+ reg8 = val & 0x0f;
+ /* Restart the PLL with the correct frequency */
+ pci_write_config8(MCU, 0x90, reg8);
+
+ /* If we have registered DIMMs, we need to set bit[0] */
+ if(dimm_is_registered(ctrl->dram_type)){
+ printram("Enabling RDIMM support in memory controller\n");
+ reg8 = pci_read_config8(MCU, 0x6c);
+ reg8 |= 1;
+ pci_write_config8(MCU, 0x6c, reg8);
+ }
+
+ /* Here we are calculating latencies, and writing them to the appropiate
+ * registers. Some registers do not take latencies from 0T, for example:
+ * CAS: 000 = 4T, 001 = 5T, 010 = 6T, etc
+ * In this example we subtract 4T from the result for CAS: (val - 4)
+ * The & 0x07 after (val - T0) just makes sure that, no matter what
+ * crazy thing may happen, we do not write outside the bits allocated
+ * in the register */
+
+ /* Find CAS latency */
+ val = (ctrl->tAA + ctrl->tCK -1) / ctrl->tCK;
+ printram("Minimum CAS latency : %uT\n", val);
+ /* Find lowest supported CAS latency that satisfies the minimum value */
+ while( !((ctrl->cas >> (val-4))&1) && (ctrl->cas >> (val-4))) val++;
+ /* Is CAS supported */
+ if(!(ctrl->cas & (1 << (val-4))) ) printram("CAS not supported\n");
+ printram("Selected CAS latency : %uT\n", val);
+ /* Write CAS latency */
+ val -= 4; /* 000 means 4T */
+ reg8 = ((val &0x07) << 4 ) | (val & 0x07);
+ pci_write_config8(MCU, 0xc0, reg8);
+
+ /* Find tRCD */
+ val = (ctrl->tRCD + ctrl->tCK -1) / ctrl->tCK;
+ printram("Selected tRCD : %uT\n", val);
+ reg8 = ((val-4) & 0x7) << 4;
+ /* Find tRP */
+ val = (ctrl->tRP + ctrl->tCK -1) / ctrl->tCK;
+ printram("Selected tRP : %uT\n", val);
+ reg8 |= ((val-4) & 0x7);
+ pci_write_config8(MCU, 0xc1, reg8);
+
+ /* Find tRAS */
+ val = (ctrl->tRAS + ctrl->tCK -1) / ctrl->tCK;
+ printram("Selected tRAS : %uT\n", val);
+ reg8 = ((val-15) & 0x7) << 4;
+ /* Find tWR */
+ val = (ctrl->tWR + ctrl->tCK -1) / ctrl->tCK;
+ printram("Selected tWR : %uT\n", val);
+ reg8 |= ((val-4) & 0x7);
+ pci_write_config8(MCU, 0xc2, reg8);
+
+ /* Find tFAW */
+ val = (ctrl->tFAW + ctrl->tCK -1) / ctrl->tCK;
+ printram("Selected tFAW : %uT\n", val);
+ reg8 = ((val-0) & 0x7) << 4;
+ /* Find tRRD */
+ val = (ctrl->tRRD + ctrl->tCK -1) / ctrl->tCK;
+ printram("Selected tRRD : %uT\n", val);
+ reg8 |= ((val-2) & 0x7);
+ pci_write_config8(MCU, 0xc3, reg8);
+
+ /* This register needs a little more attention, as bit 7 controls some
+ * other stuff:
+ * [7] 8-Bank Device Timing Constraint (See datasheet)
+ * Since all DDR3 modules are minimum 8-banks, there's no need to
+ * worry about this bit, and we can just set it;
+ * [6] Reserved
+ * [5:4] tRTP with 00 = 3T for DDR3
+ * [3] Reserved
+ * [2-0] tWTR with 000 = 2T
+ */
+ reg8 = 0x80;
+ /* Find tRTP */
+ val = (ctrl->tRTP + ctrl->tCK -1) / ctrl->tCK;
+ printram("Selected tRTP : %uT\n", val);
+ reg8 |= ((val & 0x3) << 4);
+ /* Find tWTR */
+ val = (ctrl->tWTR + ctrl->tCK -1) / ctrl->tCK;
+ printram("Selected tWTR : %uT\n", val);
+ reg8 |= ((val - 2) & 0x7);
+ pci_write_config8(MCU, 0xc4, reg8);
+
+ /* DRAM Timing for All Ranks - VI
+ * [7:6] CKE Assertion Minimum Pulse Width
+ * We probably don't want to mess with this just yet.
+ * [5:0] Refresh-to-Active or Refresh-to-Refresh (tRFC)
+ * RxC4[7] = 0:
+ * tRFC = (10 + [5:0])T
+ * RxC4[7] = 1:
+ * tRFC = (30 + 2 * [5:0])T
+ * Since we previously set RxC4[7], we're going to use this formula
+ */
+ reg8 = pci_read_config8(MCU, 0xc5);
+ val = (ctrl->tRFC + ctrl->tCK -1) / ctrl->tCK;
+ printram("Minimum tRFC : %uT\n", val);
+ if(ctrl->tRFC < 30) {
+ val = 0;
+ } else {
+ val = (val -30 + 1 ) / 2;
+ }
+ ;
+ printram("Selected tRFC : %uT\n", 30 + 2 * val);
+ reg8 |= (val & 0x1f);
+ pci_write_config8(MCU, 0xc5, reg8);
+
+ /* Where does this go??? */
+ val = (ctrl->tRC + ctrl->tCK -1) / ctrl->tCK;
+ printram("Required tRC : %uT\n", val);
+}
+
+/* The VX900 can send the MRS commands directly through hardware */
+static void vx900_dram_ddr3_do_hw_mrs(u8 ma_swap, u8 rtt_nom,
+ u8 ods, u8 rtt_wr, u8 srt, u8 asr)
+{
+ u8 reg8 = 0;
+ if(asr) reg8 |= (1 << 0);
+ if(srt) reg8 |= (1 << 1);
+ reg8 |= ((rtt_wr & 0x03) << 4);
+ pci_write_config8(MCU, 0xcd, reg8);
+ reg8 = 1;
+ if(ma_swap) reg8 |= (1 << 1);
+ reg8 |= ((ods & 0x03) << 2);
+ reg8 |= ((rtt_nom & 0x7) << 4);
+ pci_write_config8(MCU, 0xcc, reg8);
+ while(pci_read_config8(MCU, 0xcc) & 1);
+}
+#include "forgotten.h"
+#include "forgotten.c"
+static void vx900_dump_0x78_0x7f(void)
+{
+ u8 i;
+ for(i = 0x78; i < 0x80; i ++)
+ {
+ printram(" %.2x", pci_read_config8(MCU, i));
+ }
+ printram("\n");
+}
+
+static void vx900_dump_calib(const u8 what)
+{
+ u8 reg8;
+ /* Dump lower bound */
+ reg8 = ((what & 0x3) << 2) | 0x1;
+ pci_write_config8(MCU, 0x70, reg8);
+ printram("Lower bound : ");
+ vx900_dump_0x78_0x7f();
+
+ /* Dump upper bound */
+ reg8 = ((what & 0x3) << 2) | 0x2;
+ pci_write_config8(MCU, 0x70, reg8);
+ printram("Upper bound : ");
+ vx900_dump_0x78_0x7f();
+
+ /* Dump average values */
+ reg8 = ((what & 0x3) << 2);
+ pci_write_config8(MCU, 0x70, reg8);
+ printram("Average : ");
+ vx900_dump_0x78_0x7f();
+}
+
+static void vx900_dram_send_soft_mrs(u8 type, u16 cmd)
+{
+ u8 reg8;
+ u32 addr;
+ /* Set Fun3_RX6B[2:0] to 011b (MSR Enable). */
+ reg8 = pci_read_config8(MCU, 0x6b);
+ reg8 &= ~(0x03);
+ reg8 |= (3<<0);
+ pci_write_config8(MCU, 0x6b, reg8);
+ /* Find the address corresponding to the MRS */
+ addr = vx900_get_mrs_addr(type, cmd);
+ /* Execute the MRS */
+ volatile_read(addr);
+ /* Set Fun3_Rx6B[2:0] to 000b (Normal SDRAM Mode). */
+ reg8 = pci_read_config8(MCU, 0x6b);
+ reg8 &= ~(7<<0);
+ pci_write_config8(MCU, 0x6b, reg8);
+}
+static void vx900_rx_capture_range_calib(u8 pattern);
+static void vx900_rx_dqs_delay_calib(u8 pattern);
+static void vx900_tx_dq_delay_calib(void);
+static void vx900_tx_dqs_delay_calib(const u8 rank);
+
+static void vx900_delay_calib_rank(const u8 rank)
+{
+ u8 reg8, val;
+ u16 reg16;
+ printram("Starting delay calibration for rank %u\n", rank);
+
+ reg16 = 0xbbbb;
+ reg16 &= ~(0xf << (4 * rank));
+ reg16 |= (0x8 << (4 * rank));
+ pci_write_config16(MCU, 0x54, reg16);
+
+ /* MD Input Data Push Timing Control;
+ * use values recommended in datasheet */
+ reg8 = pci_read_config8(MCU, 0x74);
+ val = (TCK_533MHZ <= TCK_400MHZ)?2:1; /* FIXME*/
+ reg8 &= ~(0x03 << 1);
+ reg8 |= ((val & 0x03) << 1);
+ pci_write_config8(MCU, 0x74, reg8);
+
+ /* Disable additional delays */
+ pci_write_config8(MCU, 0xec, 0x00);
+ pci_write_config8(MCU, 0xed, 0x00);
+ pci_write_config8(MCU, 0xee, 0x00);
+
+ pci_write_config8(MCU, 0x77, 0x10);/*FIXME*/
+ const u8 pattern = 0x40; /*FIXME*/
+ //const u8 pattern = 0x00; /*FIXME*/
+ /* Run calibrations */
+ vx900_rx_capture_range_calib(pattern);
+ vx900_rx_dqs_delay_calib(pattern);
+ vx900_tx_dq_delay_calib();
+ vx900_tx_dqs_delay_calib(rank);
+}
+
+static void vx900_rx_capture_range_calib(u8 pattern)
+{
+ u8 reg8;
+ u16 cmd;
+ /*
+ * Calibration of RX Capture Range can be triggered by setting
+ * Rx71[5] to 1.
+ * The process started by sending a series of read commands on the DRAM
+ * bus with different setting for the RX Capture Range.
+ *
+ * After a MRS (Mode Register Set) command to put DDR3 in a mode called
+ * “Read Leveling Mode”,
+ */
+ /* Put DRAM in read leveling mode */
+ cmd = ddr3_get_mr3(1);
+ vx900_dram_send_soft_mrs(3, cmd);
+
+ /* DDR3 returned the read command with a predefined
+ * data pattern either “00h-01h-00h-01h” or “00h-FFh-00h-FFh”. There is
+ * no specific definition in the current DDR3 specification for this
+ * pattern, so, the working software might need to do the calibration
+ * twice. It could triggered the scanning with
+ * Rx71[6] set to 1 first.
+ * If nothing can be working right, the software trigger the scanning
+ * again with
+ * Rx71[6] set to 0.
+ * The controller thus can check those pattern to verify if the data
+ * from DDR3 DIMM is correct or not. The calibration will work from the
+ * lowest limit of the setting for the RX Capture Range, it marked the
+ * setting for its lower bound when checking is correct. It increased
+ * the setting and issued read cycle again and again until checking of
+ * the data is incorrect. It then marked the last working setting as
+ * the upper bound.
+ * Controller also calculated the average of the lower bound and upper
+ * bound to have the center of the setting, which presumably the most
+ * stable one. Besides this capture range setting, there is another set
+ * of delay control for internal MD paths at RxEF[5:4].
+ * However, that one is independent of the calibration mechanism here.*/
+ /* Data pattern must be 0x00 for this calibration */
+ pci_write_config8(MCU, 0x8e, 0x00);
+ /* Trigger calibration */
+ reg8 = 0xa0 | (pattern & 0x40);
+ pci_write_config8(MCU, 0x71, reg8);
+
+ printram("RX capture range calibration results:\n");
+ vx900_dump_calib(3);
+
+ /* Disable read leveling, and put dram in normal operation mode */
+ cmd = ddr3_get_mr3(0);
+ vx900_dram_send_soft_mrs(3, cmd);
+}
+
+static void vx900_rx_dqs_delay_calib(u8 pattern)
+{
+ u8 reg8;
+ /* The same process is done by setting
+ * Rx71[1] to 1
+ * to start the calibration for RX DQS Delay. Besides the manual
+ * setting, there is also a setting which is calculated by using
+ * internal DCLK DLL to have a 1/4T delay for DQS.
+ * Noted that when this option is set
+ * (Rx71[2] =1)
+ * the DQS of all the bytes (MDQS[7:0]P/N) will use this self-calculated
+ * 1/4 delay setting. */
+
+ /* Data pattern must be 0x00 for this calibration */
+ pci_write_config8(MCU, 0x8e, 0x00);
+ /* Trigger calibration */
+ reg8 = 0x82 | (pattern & 0x40);
+ pci_write_config8(MCU, 0x71, reg8);
+
+ printram("RX DQS delay calibration results:\n");
+ vx900_dump_calib(2);
+}
+static void vx900_tx_dq_delay_calib()
+{
+ /* The calibration for TX DQ Delay is started once
+ * Rx75[1] is set to 1.
+ * That process is to issue a write with
+ * data defined by Rx8E[7:0]
+ * and to issue a read command right after it to do the checking.
+ * Before issuing the write command, the calibration controller will set
+ * the setting of TX DQ Delay. It started with the smallest setting, and
+ * it will mark the one as lower bound when the corresponding checking
+ * is right. It continue with the write + read + checking processes and
+ * see if it started to fail. The last working setting is the upper
+ * bound. This process will not stop until all the upper bound are found
+ * for all the bytes. */
+ /* Data pattern for calibration */
+ pci_write_config8(MCU, 0x8e, 0x5a);
+ /* Trigger calibration */
+ pci_write_config8(MCU, 0x75, 0x02);
+
+ printram("TX DQ delay calibration results:\n");
+ vx900_dump_calib(1);
+}
+static void vx900_tx_dqs_delay_calib(const u8 rank)
+{
+ u8 reg8;
+ u16 cmd;
+ /* Noted that there are two types of calibration for the TX DQS Delay.
+ * Setting Rx75[5] to 1,
+ * the calibration process will go as that of TX DQ Delay. Only that the
+ * adjustment made is on the TX DQS output path not the TX DQ output
+ * path. There is another way of calibration worked with DDR3 DRAM
+ * called “Write Leveling”. The procedure would be
+ * 1) Set Rx9E[3:2] to select which Rank to do write leveling.
+ * 2) Issue MRS commands to each Rank of DRAM to let them know which one
+ * is enabled for Write leveling.
+ * 3) Set Rx75[2] to 1 to trigger the operation.
+ * After step 3, the controller will adjust the TX DQS delay by one step
+ * and send a pulse of DQS out to DRAM. The bit0 of MD of a byte
+ * (MD0, MD8, MD16, .. MD57) will return the status (“high” or “low”) of
+ * DCLK the selected Rank sensed. The controller will continue adjusting
+ * the delay and sending a pulse of MDQS out. This scheme is to detect
+ * the MDQS delay against the DCLK’s rising and falling edge. Thus we
+ * can know where the lower bound of the TX DQS setting is when the
+ * falling edge of DCLK is found, and where the upper bound of the
+ * TX DQS setting is when the rising edge of DCLK is found by the DRAM.
+ * With the upper bound and lower bound, we can choose the middle point
+ * as the setting for the calibration (scan) result. */
+
+ reg8 = pci_read_config8(MCU, 0x9e);
+ reg8 &= ~(3 << 2);
+ reg8 |= ((rank & 0x3) << 2);
+ pci_write_config8(MCU, 0x9e, reg8);
+ cmd = ddr3_get_mr1(0, 0, 0, 1, 0, 0, 0);
+ vx900_dram_send_soft_mrs(1, cmd);
+ /* Data pattern for calibration */
+ pci_write_config8(MCU, 0x8e, 0x5a);
+ /* Trigger calibration */
+ pci_write_config8(MCU, 0x75, 0x04);
+ printram("TX DQS delay calibration results:\n");
+ vx900_dump_calib(0);
+ cmd = ddr3_get_mr1(0, 0, 0, 0, 0, 0, 0);
+ vx900_dram_send_soft_mrs(1, cmd);
+
+}
+
+static void vx900_dram_ddr3_dimm_init(const ramctr_timing *ctrl,
+ const rank_layout *ranks)
+{
+ u8 reg8;
+ size_t i;
+
+ /* Step 01 - Set Fun3_Rx6E[5] to 1b to support burst length. */
+ /* This is set at init time
+ reg8 = pci_read_config8(MCU, 0x6e);
+ reg8 |= (1<<5);
+ pci_write_config8(MCU, 0x6e, reg8);*/
+ /* Step 02 - Set Fun3_RX69[0] to 0b (Disable Multiple Page Mode). */
+ reg8 = pci_read_config8(MCU, 0x69);
+ reg8 &= ~(1<<0);
+ pci_write_config8(MCU, 0x69, reg8);
+
+ /* Step 03 - Set the target physical rank to virtual rank0 and other
+ * ranks to virtual rank3. If physical rank0 init is desired,
+ * set Fun3_Rx54 to 08Bh and Fun3_Rx55=0BBh. */
+ pci_write_config16(MCU, 0x54, 0xbbb8);
+
+ /* Step 04 - Set Fun3_Rx50 to D8h. */
+ pci_write_config8(MCU, 0x50, 0xd8);
+ /* Step 05 - Set Fun3_RX6B[5] to 1b to de-assert RESET# and wait for at
+ * least 500 us. */
+ reg8 = pci_read_config8(MCU, 0x6b);
+ reg8 |= (1<<5);
+ pci_write_config8(MCU, 0x6b, reg8);
+ for(i = 0; i < 500; i++) inb(0x80);
+
+ for(i = 0; i < VX900_MAX_MEM_RANKS; i++)
+ {
+ u16 reg16;
+ if(ranks->phys_rank_size[i] == 0) continue;
+ printram("Initializing rank %lu\n", i);
+
+ const u8 rtt_nom = 2;
+ const u8 ods = 0;
+ const u8 rtt_wr = 1;
+
+ reg16 = 0xbbbb;
+ reg16 &= ~(0xf << (4 * i));
+ reg16 |= (0x8 << (4 * i));
+ pci_write_config16(MCU, 0x54, reg16);
+ vx900_dram_ddr3_do_hw_mrs(0, rtt_nom, ods, rtt_wr, 0, 0);
+ vx900_delay_calib_rank(i);
+ }
+ /* Step 15 – Set the next target physical rank to virtual rank 0 and
+ * other ranks to virtual rank 3. Repeat Step 6 to 14, then jump to
+ * Step 16. */
+
+ /* Step 16 – Set Fun3_Rx6B[2:0] to 000b (Normal SDRAM Mode). */
+ reg8 = pci_read_config8(MCU, 0x6b);
+ reg8 &= ~(7<<0);
+ pci_write_config8(MCU, 0x6b, reg8);
+
+ /* Step 17 – Set Fun3_Rx69[0] to 1b (Enable Multiple Page Mode). */
+ reg8 = pci_read_config8(MCU, 0x69);
+ reg8 |= (1<<0);
+ pci_write_config8(MCU, 0x69, reg8);
+
+ printram("DRAM initialization sequence complete\n");
+}
+
+static void print_debug_pci_dev(device_t dev)
+{
+ print_debug("PCI: ");
+ print_debug_hex8((dev >> 20) & 0xff);
+ print_debug_char(':');
+ print_debug_hex8((dev >> 15) & 0x1f);
+ print_debug_char('.');
+ print_debug_hex8((dev >> 12) & 7);
+}
+
+static void dump_pci_device(device_t dev)
+{
+ int i;
+ print_debug_pci_dev(dev);
+ print_debug("\n");
+
+ for (i = 0; i <= 255; i++) {
+ unsigned char val;
+ if ((i & 0x0f) == 0) {
+ print_debug_hex8(i);
+ print_debug_char(':');
+ }
+
+ if ((i & 0x0f) == 0x08) {
+ print_debug(" |");
+ }
+
+ val = pci_read_config8(dev, i);
+ print_debug_char(' ');
+ print_debug_hex8(val);
+
+ if ((i & 0x0f) == 0x0f) {
+ print_debug("\n");
+ }
+ }
+}
+
+static void vx900_dram_write_final_config(ramctr_timing *ctrl)
+{
+ u8 reg8;
+ /* Set DRAM refresh counter
+ * Based on a refresh counter of 0x61 at 400MHz */
+ reg8 = (TCK_400MHZ * 0x61) / ctrl->tCK;
+ pci_write_config8(MCU, 0xc7, reg8);
+
+ /* My cheat sheet */
+ size_t i;
+ for(i = 0; i < (sizeof(mcu_cheat_sheet)/sizeof(pci_reg8)); i++)
+ pci_write_config8(MCU, mcu_cheat_sheet[i].addr,
+ mcu_cheat_sheet[i].val);
+}
+
+void vx900_init_dram_ddr3(const dimm_layout *dimm_addr)
+{
+ dimm_info dimm_prop;
+ ramctr_timing ctrl_prop;
+ rank_layout ranks;
+ device_t mcu;
+ /* Locate the Memory controller */
+ mcu = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_VX900_DRAM_CTR), 0);
+
+ if (mcu == PCI_DEV_INVALID) {
+ die("Memory Controller not found\n");
+ }
+
+ memset(&ranks, 0, sizeof(ranks));
+ /* 1) Write some initial "safe" parameters */
+ vx900_dram_write_init_config();
+ /* 2) Get timing information from SPDs */
+ dram_find_spds_ddr3(dimm_addr, &dimm_prop);
+ /* 3) Find lowest common denominator for all modules */
+ dram_find_common_params(&dimm_prop, &ctrl_prop);
+ /* 4) Find the size of each memory rank */
+ vx900_dram_phys_bank_range(&dimm_prop, &ranks);
+ /* 5) Set DRAM driving strength */
+ vx900_dram_driving_ctrl();
+ /* 6) Set DRAM frequency and latencies */
+ vx900_dram_freq_latency(&ctrl_prop);
+ /* 7) Initialize the modules themselves */
+ vx900_dram_ddr3_dimm_init(&ctrl_prop, &ranks);
+ /* 8) Enable Physical to Virtual Rank mapping */
+ vx900_dram_range(&ctrl_prop, &ranks);
+ /* 99) Some final adjustments */
+ vx900_dram_write_final_config(&ctrl_prop);
+ /* Take a dump */
+ dump_pci_device(mcu);
+
+}
diff --git a/src/northbridge/via/vx900/romstrap.inc b/src/northbridge/via/vx900/romstrap.inc
new file mode 100644
index 0000000..8e54627
--- /dev/null
+++ b/src/northbridge/via/vx900/romstrap.inc
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2004 Tyan Computer
+ * (Written by Yinghai Lu <yhlu(a)tyan.com> for Tyan Computer)
+ * Copyright (C) 2007 Rudolf Marek <r.marek(a)assembler.cz>
+ * Copyright (C) 2009 One Laptop per Child, Association, Inc.
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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; 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.
+ *
+ * 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
+ */
+
+/* This file constructs the ROM strap table for VX900 */
+
+ .section ".romstrap", "a", @progbits
+
+ .globl __romstrap_start
+__romstrap_start:
+tblpointer:
+ .long 0x77886047
+ .long 0x00777777
+ .long 0x00000000
+ .long 0x00000000
+ .long 0x00888888
+ .long 0x00AA1111
+ .long 0x00000000
+ .long 0x00000000
+
+/*
+ * The pointer to above table should be at 0xffffffd0,
+ * the table itself MUST be aligned to 128B it seems!
+ */
+rspointers:
+ .long tblpointer // It will be 0xffffffd0
+
+ .globl __romstrap_end
+
+__romstrap_end:
+.previous
diff --git a/src/northbridge/via/vx900/romstrap.lds b/src/northbridge/via/vx900/romstrap.lds
new file mode 100644
index 0000000..b51c979
--- /dev/null
+++ b/src/northbridge/via/vx900/romstrap.lds
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 AMD
+ * (Written by Yinghai Lu <yinghai.lu(a)amd.com> for AMD)
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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 3 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, see <http://www.gnu.org/licenses/>
+ */
+
+SECTIONS {
+ . = (0x100000000 - 0x2c) - (__romstrap_end - __romstrap_start);
+ .romstrap (.): {
+ *(.romstrap)
+ }
+}
diff --git a/src/northbridge/via/vx900/vx900.h b/src/northbridge/via/vx900/vx900.h
new file mode 100644
index 0000000..2137daf
--- /dev/null
+++ b/src/northbridge/via/vx900/vx900.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Alexandru Gagniuc <mr.nuke.me(a)gmail.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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define VX800_ACPI_IO_BASE 0x0400
+
+#define VX900_NB_IOAPIC_ID 0x2
+#define VX900_NB_IOAPIC_BASE 0xfecc000
+
+#define VX900_SB_IOAPIC_ID 0x1
+#define VX900_SB_IOAPIC_BASE 0xfec0000
\ No newline at end of file
Hi,
I have old Asus M3A78-EM [1] board inside my HTPC. I'm looking to
speed up the boot process of my HTPC. I have heard that coreboot can
boot directly into Linux or GRUB. I checked the supported list and
found out that my board is not on the list, but at the same time I see
that very similar board Asus M4A78-EM [2] is on and supported well. So
I am wondering how difficult and how much work wold be required to
port coreboot to my board.
Secondary question would be if I have to upgrade my HTPC witch board
would be better for using with coreboot: Intel i3-2100T based system
or AMD E-350 based?
Thank you,
SAL-e
[1] http://www.asus.com/Motherboards/AMD_AM2Plus/M3A78EM/
[2] http://www.asus.com/Motherboards/AMD_AM2Plus/M4A78EM/
PS. Please replay directly or CC in your reply to me, because I am not
member of the list yet. 10x
I've just seen these news about a new vehicle PC with
5 seconds boot time thanks to coreboot, but there is
no information on pricing, software (if any, maybe it
is sold without hard disks ?) or firmware (apparently
they would ship it with coreboot, but the datasheet
does only say "supports AMD Coreboot technology",
which might mean that the user can install it and
it should work, although I'd think it's more likely
to mean it comes preinstalled.
If so it may even be tempting. Pity my only vehicles
are bicyles and I'm not sure what to use the 1.5 kg
+ disks + screen+ power source for while riding...
I guess you can also use it at home, but I wonder about
the price (no , I'm not going to ask them because I
wasn't thinking of buying a new computer now, but I'm curious).
http://www.linuxfordevices.com/c/a/News/Portwell-PCS8277/http://www.portwell.com/products/detail.asp?CUSTCHAR1=PCS-8277#order
In any case, congratulations all, it looks like another
milestone.
Time to start a new section in the web about "where to buy?"
the following patch was just integrated into master:
commit 6c91eea77c72c1ca87601f08be48711b7f6080d2
Author: Alec Ari <neotheuser(a)ymail.com>
Date: Sun Aug 21 22:17:35 2011 -0500
Remove dead code
Remove dead code, copy and pasted from
tilapia's mainboard.c file into various
asus mainboard.c files
Change-Id: Ic715ccaad8ac0210401d4a99ecb11e943f6afe58
Signed-off-by: Alec Ari <neotheuser(a)ymail.com>
See http://review.coreboot.org/168 for details.
-gerrit
Seller Updates:
Model: Lenovo Thinkpad T60p 8742 Z19 (absent: seems Y19)
CPU: Core 2 Duo T7200
Notrthbridge: 945PM Express
Southbridge: ICH7-M
SuperI/O: Renesas H8S2161B (not confirmed at all)
Socket: 479
So as long as 945PM is uopon 945 family and ICH7-M is upon ICH7, i'll go
for it ;)
Note: as long as Renesas H8S2161B is not officially on the table, but
fortunately is not related for graphics issues, i'll proceed on getting
through it and try to look at
Best Regards, Matias
<P><p><font face="Arial, Helvetica, sans-serif" size="2" style="font-size:13.5px">_______________________________________________________________<BR>Care2 makes it easy for everyone to live a healthy, green lifestyle
and impact the causes you care about most. Over 12 Million members!
http://www.care2.com
Feed a child by searching the web! Learn how http://www.care2.com/toolbar</font>
Frank Vibrans III (frank.vibrans(a)amd.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/138
-gerrit
commit 37e9953a65ff20464fc04254bcec3805b0fa926d
Author: efdesign98 <efdesign98(a)gmail.com>
Date: Fri Aug 19 14:25:48 2011 -0600
AMD Torpedo platform updates
This update fixes warnings and supports as necessary
the Agesa infrastructure changes required to support
the AMD Family 14 cpu update to rev C0.
Change-Id: Ib08b49695b925b81f796bf299141fe6f845fdef8
Signed-off-by: Frank Vibrans <frank.vibrans(a)amd.com>
Signed-off-by: efdesign98 <efdesign98(a)gmail.com>
---
src/mainboard/amd/torpedo/BiosCallOuts.c | 24 ++++++----
src/mainboard/amd/torpedo/Kconfig | 18 ++++----
src/mainboard/amd/torpedo/Oem.h | 72 +++++++----------------------
src/mainboard/amd/torpedo/agesawrapper.h | 1 -
src/mainboard/amd/torpedo/get_bus_conf.c | 1 +
5 files changed, 42 insertions(+), 74 deletions(-)
diff --git a/src/mainboard/amd/torpedo/BiosCallOuts.c b/src/mainboard/amd/torpedo/BiosCallOuts.c
index ff55e24..f8d584d 100755
--- a/src/mainboard/amd/torpedo/BiosCallOuts.c
+++ b/src/mainboard/amd/torpedo/BiosCallOuts.c
@@ -525,7 +525,6 @@ AGESA_STATUS BiosHookBeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
UINT32 GpioMmioAddr;
UINT8 Data8;
UINT16 Data16;
- UINT8 TempData8;
FcnData = Data;
MemData = ConfigPtr;
@@ -540,25 +539,30 @@ AGESA_STATUS BiosHookBeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
Data16 |= Data8;
AcpiMmioAddr = (UINT32)Data16 << 16;
GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
- if(MemData->ParameterListPtr->DDR3Voltage == VOLT1_5) {
- Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG178);
- Data8 |= BIT6;
- Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
- } else if(MemData->ParameterListPtr->DDR3Voltage == VOLT1_35) {
+
+ switch(MemData->ParameterListPtr->DDR3Voltage){
+ case VOLT1_35:
Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
Data8 &= ~(UINT8)BIT6;
Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
- Data8 |= BIT6;
+ Data8 |= (UINT8)BIT6;
Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
- } else if(MemData->ParameterListPtr->DDR3Voltage == VOLT1_25) {
+ break;
+ case VOLT1_25:
Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
Data8 &= ~(UINT8)BIT6;
Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG179);
Data8 &= ~(UINT8)BIT6;
Write64Mem8(GpioMmioAddr+SB_GPIO_REG179, Data8);
- } else {}
+ break;
+ case VOLT1_5:
+ default:
+ Data8 = Read64Mem8 (GpioMmioAddr+SB_GPIO_REG178);
+ Data8 |= (UINT8)BIT6;
+ Write64Mem8(GpioMmioAddr+SB_GPIO_REG178, Data8);
+ }
return Status;
}
@@ -598,7 +602,7 @@ AGESA_STATUS BiosGnbPcieSlotReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
GpioMmioAddr = AcpiMmioAddr + GPIO_BASE;
if (ResetInfo->ResetControl == DeassertSlotReset) {
- if (ResetInfo->ResetId & BIT2+BIT3) { //de-assert
+ if (ResetInfo->ResetId & (BIT2+BIT3)) { //de-assert
// [GPIO] GPIO45: PE_GPIO1 MXM_POWER_ENABLE, SET HIGH
Data8 = Read64Mem8(GpioMmioAddr+SB_GPIO_REG45);
if (Data8 & BIT7) {
diff --git a/src/mainboard/amd/torpedo/Kconfig b/src/mainboard/amd/torpedo/Kconfig
index 57d8c05..16d4cd0 100755
--- a/src/mainboard/amd/torpedo/Kconfig
+++ b/src/mainboard/amd/torpedo/Kconfig
@@ -1,7 +1,7 @@
#
# This file is part of the coreboot project.
#
-# Copyright (C) 2010 Advanced Micro Devices, Inc.
+# Copyright (C) 2011 Advanced Micro Devices, Inc.
#
# 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
@@ -126,14 +126,6 @@ config SIO_PORT
hex
default 0x2e
-config DRIVERS_PS2_KEYBOARD
- bool
- default y
-
-config WARNINGS_ARE_ERRORS
- bool
- default n
-
config ONBOARD_VGA_IS_PRIMARY
bool
default y
@@ -180,6 +172,14 @@ config XHC_BIOS_ID
depends on XHC_BIOS
default "1022,7812"
+config DRIVERS_PS2_KEYBOARD
+ bool
+ default y
+
+config WARNINGS_ARE_ERRORS
+ bool
+ default n
+
config CONSOLE_POST
bool
depends on !NO_POST
diff --git a/src/mainboard/amd/torpedo/Oem.h b/src/mainboard/amd/torpedo/Oem.h
index 50bb506..a7109dc 100755
--- a/src/mainboard/amd/torpedo/Oem.h
+++ b/src/mainboard/amd/torpedo/Oem.h
@@ -1,57 +1,21 @@
-/*;********************************************************************************
-;
-; Copyright 2011 ADVANCED MICRO DEVICES, INC. All Rights Reserved.
-;
-; AMD is granting you permission to use this software (the Materials)
-; pursuant to the terms and conditions of your Software License Agreement
-; with AMD. This header does *NOT* give you permission to use the Materials
-; or any rights under AMD's intellectual property. Your use of any portion
-; of these Materials shall constitute your acceptance of those terms and
-; conditions. If you do not agree to the terms and conditions of the Software
-; License Agreement, please do not use any portion of these Materials.
-;
-; CONFIDENTIALITY: The Materials and all other information, identified as
-; confidential and provided to you by AMD shall be kept confidential in
-; accordance with the terms and conditions of the Software License Agreement.
-;
-; LIMITATION OF LIABILITY: THE MATERIALS AND ANY OTHER RELATED INFORMATION
-; PROVIDED TO YOU BY AMD ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED
-; WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
-; MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY PARTICULAR PURPOSE,
-; OR WARRANTIES ARISING FROM CONDUCT, COURSE OF DEALING, OR USAGE OF TRADE.
-; IN NO EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES WHATSOEVER
-; (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS
-; INTERRUPTION, OR LOSS OF INFORMATION) ARISING OUT OF AMD'S NEGLIGENCE,
-; GROSS NEGLIGENCE, THE USE OF OR INABILITY TO USE THE MATERIALS OR ANY OTHER
-; RELATED INFORMATION PROVIDED TO YOU BY AMD, EVEN IF AMD HAS BEEN ADVISED OF
-; THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE
-; EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES,
-; THE ABOVE LIMITATION MAY NOT APPLY TO YOU.
-;
-; AMD does not assume any responsibility for any errors which may appear in
-; the Materials or any other related information provided to you by AMD, or
-; result from use of the Materials or any related information.
-;
-; You agree that you will not reverse engineer or decompile the Materials.
-;
-; NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any
-; further information, software, technical information, know-how, or show-how
-; available to you. Additionally, AMD retains the right to modify the
-; Materials at any time, without notice, and is not obligated to provide such
-; modified Materials to you.
-;
-; U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with
-; "RESTRICTED RIGHTS." Use, duplication, or disclosure by the Government is
-; subject to the restrictions as set forth in FAR 52.227-14 and
-; DFAR252.227-7013, et seq., or its successor. Use of the Materials by the
-; Government constitutes acknowledgement of AMD's proprietary rights in them.
-;
-; EXPORT ASSURANCE: You agree and certify that neither the Materials, nor any
-; direct product thereof will be exported directly or indirectly, into any
-; country prohibited by the United States Export Administration Act and the
-; regulations thereunder, without the required authorization from the U.S.
-; government nor will be used for any purpose prohibited by the same.
-;*********************************************************************************/
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Advanced Micro Devices, Inc.
+ *
+ * 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.
+ *
+ * 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
+ */
#define BIOS_SIZE 0x04 //04 - 1MB
#define LEGACY_FREE 0x00
diff --git a/src/mainboard/amd/torpedo/agesawrapper.h b/src/mainboard/amd/torpedo/agesawrapper.h
index 979f743..c3209f5 100755
--- a/src/mainboard/amd/torpedo/agesawrapper.h
+++ b/src/mainboard/amd/torpedo/agesawrapper.h
@@ -118,7 +118,6 @@ typedef struct {
*---------------------------------------------------------------------------------------
*/
-//void brazos_platform_stage(void);
UINT32 agesawrapper_amdinitreset (void);
UINT32 agesawrapper_amdinitearly (void);
UINT32 agesawrapper_amdinitenv (void);
diff --git a/src/mainboard/amd/torpedo/get_bus_conf.c b/src/mainboard/amd/torpedo/get_bus_conf.c
index 436f6a8..f9b4c84 100755
--- a/src/mainboard/amd/torpedo/get_bus_conf.c
+++ b/src/mainboard/amd/torpedo/get_bus_conf.c
@@ -24,6 +24,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <cpu/amd/amdfam12.h>
+#include "SbEarly.h"
#include "agesawrapper.h"