-#include <cpu/x86/mtrr.h>
-#include "raminit.h"
-
-/*
-This software and ancillary information (herein called SOFTWARE )
-called LinuxBIOS is made available under the terms described
-here. The SOFTWARE has been approved for release with associated
-LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
-been authored by an employee or employees of the University of
-California, operator of the Los Alamos National Laboratory under
-Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
-U.S. Government has rights to use, reproduce, and distribute this
-SOFTWARE. The public may copy, distribute, prepare derivative works
-and publicly display this SOFTWARE without charge, provided that this
-Notice and any statement of authorship are reproduced on all copies.
-Neither the Government nor the University makes any warranty, express
-or implied, or assumes any liability or responsibility for the use of
-this SOFTWARE. If SOFTWARE is modified to produce derivative works,
-such modified SOFTWARE should be clearly marked, so as not to confuse
-it with the version available from LANL.
- */
-/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
- * rminnich@lanl.gov
- */
/*
- * 11/26/02 - kevinh@ispiri.com - The existing comments implied that
- * this didn't work yet. Therefore, I've updated it so that it works
- * correctly - at least on my VIA epia motherboard. 64MB DIMM in slot 0.
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007-2008 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2010 Keith Hui <buurin@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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/* Added automatic detection of first equipped bank and its MA mapping type.
- * (Rest of configuration is done in C)
- * 5/19/03 by SONE Takeshi <ts1@tsn.or.jp>
- */
-/* converted to C 9/2003 Ron Minnich */
+#include <spd.h>
+#include <delay.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <arch/io.h>
+#include <arch/romcc_io.h>
+#include <device/pci_def.h>
+#include <console/console.h>
+#include "i440bx.h"
+#include "raminit.h"
-/* Modified for the i440bx Richard Smith 01/2005 */
+/*-----------------------------------------------------------------------------
+Macros and definitions.
+-----------------------------------------------------------------------------*/
-/* Set to 1 if your DIMMs are PC133 Note that I'm assuming CPU's FSB
- * frequency is 133MHz. If your CPU runs at another bus speed, you
- * might need to change some of register values.
- */
-#ifndef DIMM_PC133
-#define DIMM_PC133 0
+#define NB PCI_DEV(0, 0, 0)
+
+/* Debugging macros. */
+#if CONFIG_DEBUG_RAM_SETUP
+#define PRINT_DEBUG(x...) printk(BIOS_DEBUG, x)
+#define DUMPNORTH() dump_pci_device(NB)
+#else
+#define PRINT_DEBUG(x...)
+#define DUMPNORTH()
#endif
-// Set to 1 if your DIMMs are CL=2
-#ifndef DIMM_CL2
-#define DIMM_CL2 0
+/* SDRAMC[7:5] - SDRAM Mode Select (SMS). */
+#define RAM_COMMAND_NORMAL 0x0
+#define RAM_COMMAND_NOP 0x1
+#define RAM_COMMAND_PRECHARGE 0x2
+#define RAM_COMMAND_MRS 0x3
+#define RAM_COMMAND_CBR 0x4
+
+/* Map the JEDEC SPD refresh rates (array index) to 440BX refresh rates as
+ * defined in DRAMC[2:0].
+ *
+ * [0] == Normal 15.625 us -> 15.6 us
+ * [1] == Reduced(.25X) 3.9 us -> 7.8 ns
+ * [2] == Reduced(.5X) 7.8 us -> 7.8 us
+ * [3] == Extended(2x) 31.3 us -> 31.2 us
+ * [4] == Extended(4x) 62.5 us -> 62.4 us
+ * [5] == Extended(8x) 125 us -> 124.8 us
+ */
+static const uint32_t refresh_rate_map[] = {
+ 1, 5, 5, 2, 3, 4
+};
+
+/* Table format: register, bitmask, value. */
+static const u8 register_values[] = {
+ /* NBXCFG - NBX Configuration Register
+ * 0x50 - 0x53
+ *
+ * [31:24] SDRAM Row Without ECC
+ * 0 = ECC components are populated in this row
+ * 1 = ECC components are not populated in this row
+ * [23:19] Reserved
+ * [18:18] Host Bus Fast Data Ready Enable (HBFDRE)
+ * Assertion of DRAM data on host bus occurs...
+ * 0 = ...one clock after sampling snoop results (default)
+ * 1 = ...on the same clock the snoop result is being sampled
+ * (this mode is faster by one clock cycle)
+ * [17:17] ECC - EDO static Drive mode
+ * 0 = Normal mode (default)
+ * 1 = ECC signals are always driven
+ * [16:16] IDSEL_REDIRECT
+ * 0 = IDSEL1 is allocated to this bridge (default)
+ * 1 = IDSEL7 is allocated to this bridge
+ * [15:15] WSC# Handshake Disable
+ * 1 = Uni-processor mode
+ * 0 = Dual-processor mode with external IOAPIC (default)
+ * [14:14] Intel Reserved
+ * [13:12] Host/DRAM Frequency
+ * 00 = 100 MHz
+ * 01 = Reserved
+ * 10 = 66 MHz
+ * 11 = Reserved
+ * [11:11] AGP to PCI Access Enable
+ * 1 = Enable
+ * 0 = Disable
+ * [10:10] PCI Agent to Aperture Access Disable
+ * 1 = Disable
+ * 0 = Enable (default)
+ * [09:09] Aperture Access Global Enable
+ * 1 = Enable
+ * 0 = Disable
+ * [08:07] DRAM Data Integrity Mode (DDIM)
+ * 00 = Non-ECC
+ * 01 = EC-only
+ * 10 = ECC Mode
+ * 11 = ECC Mode with hardware scrubbing enabled
+ * [06:06] ECC Diagnostic Mode Enable (EDME)
+ * 1 = Enable
+ * 0 = Normal operation mode (default)
+ * [05:05] MDA Present (MDAP)
+ * Works in conjunction with the VGA_EN bit.
+ * VGA_EN MDAP
+ * 0 x All VGA cycles are sent to PCI
+ * 1 0 All VGA cycles are sent to AGP
+ * 1 1 All VGA cycles are sent to AGP, except for
+ * cycles in the MDA range.
+ * [04:04] Reserved
+ * [03:03] USWC Write Post During I/O Bridge Access Enable (UWPIO)
+ * 1 = Enable
+ * 0 = Disable
+ * [02:02] In-Order Queue Depth (IOQD)
+ * 1 = In-order queue = maximum
+ * 0 = A7# is sampled asserted (i.e., 0)
+ * [01:00] Reserved
+ */
+ NBXCFG + 0, 0x00, 0x0c,
+ // TODO: Bit 15 should be 0 for multiprocessor boards
+ NBXCFG + 1, 0x00, 0x80,
+ NBXCFG + 2, 0x00, 0x00,
+ NBXCFG + 3, 0x00, 0xff,
+
+ /* DRAMC - DRAM Control Register
+ * 0x57
+ *
+ * [7:6] Reserved
+ * [5:5] Module Mode Configuration (MMCONFIG)
+ * The combination of SDRAMPWR and this bit (which is set by an
+ * external strapping option) determine how CKE works.
+ * SDRAMPWR MMCONFIG
+ * 0 0 = 3 DIMM, CKE0[5:0] driven
+ * X 1 = 3 DIMM, CKE0 only
+ * 1 0 = 4 DIMM, GCKE only
+ * [4:3] DRAM Type (DT)
+ * 00 = EDO
+ * 01 = SDRAM
+ * 10 = Registered SDRAM
+ * 11 = Reserved
+ * Note: EDO, SDRAM and Registered SDRAM cannot be mixed.
+ * [2:0] DRAM Refresh Rate (DRR)
+ * 000 = Refresh disabled
+ * 001 = 15.6 us
+ * 010 = 31.2 us
+ * 011 = 62.4 us
+ * 100 = 124.8 us
+ * 101 = 249.6 us
+ * 110 = Reserved
+ * 111 = Reserved
+ */
+ /* Choose SDRAM (not registered), and disable refresh for now. */
+ DRAMC, 0x00, 0x08,
+
+ /*
+ * PAM[6:0] - Programmable Attribute Map Registers
+ * 0x59 - 0x5f
+ *
+ * 0x59 [3:0] Reserved
+ * 0x59 [5:4] 0xF0000 - 0xFFFFF BIOS area
+ * 0x5a [1:0] 0xC0000 - 0xC3FFF ISA add-on BIOS
+ * 0x5a [5:4] 0xC4000 - 0xC7FFF ISA add-on BIOS
+ * 0x5b [1:0] 0xC8000 - 0xCBFFF ISA add-on BIOS
+ * 0x5b [5:4] 0xCC000 - 0xCFFFF ISA add-on BIOS
+ * 0x5c [1:0] 0xD0000 - 0xD3FFF ISA add-on BIOS
+ * 0x5c [5:4] 0xD4000 - 0xD7FFF ISA add-on BIOS
+ * 0x5d [1:0] 0xD8000 - 0xDBFFF ISA add-on BIOS
+ * 0x5d [5:4] 0xDC000 - 0xDFFFF ISA add-on BIOS
+ * 0x5e [1:0] 0xE0000 - 0xE3FFF BIOS entension
+ * 0x5e [5:4] 0xE4000 - 0xE7FFF BIOS entension
+ * 0x5f [1:0] 0xE8000 - 0xEBFFF BIOS entension
+ * 0x5f [5:4] 0xEC000 - 0xEFFFF BIOS entension
+ *
+ * Bit assignment:
+ * 00 = DRAM Disabled (all access goes to memory mapped I/O space)
+ * 01 = Read Only (Reads to DRAM, writes to memory mapped I/O space)
+ * 10 = Write Only (Writes to DRAM, reads to memory mapped I/O space)
+ * 11 = Read/Write (all access goes to DRAM)
+ */
+
+ /*
+ * Map all legacy regions to RAM (read/write). This is required if
+ * you want to use the RAM area from 768 KB - 1 MB. If the PAM
+ * registers are not set here appropriately, the RAM in that region
+ * will not be accessible, thus a RAM check of it will also fail.
+ *
+ * TODO: This was set in sdram_set_spd_registers().
+ * Test if it still works when set here.
+ */
+ PAM0, 0x00, 0x30,
+ PAM1, 0x00, 0x33,
+ PAM2, 0x00, 0x33,
+ PAM3, 0x00, 0x33,
+ PAM4, 0x00, 0x33,
+ PAM5, 0x00, 0x33,
+ PAM6, 0x00, 0x33,
+
+ /* DRB[0:7] - DRAM Row Boundary Registers
+ * 0x60 - 0x67
+ *
+ * An array of 8 byte registers, which hold the ending memory address
+ * assigned to each pair of DIMMs, in 8MB granularity.
+ *
+ * 0x60 DRB0 = Total memory in row0 (in 8 MB)
+ * 0x61 DRB1 = Total memory in row0+1 (in 8 MB)
+ * 0x62 DRB2 = Total memory in row0+1+2 (in 8 MB)
+ * 0x63 DRB3 = Total memory in row0+1+2+3 (in 8 MB)
+ * 0x64 DRB4 = Total memory in row0+1+2+3+4 (in 8 MB)
+ * 0x65 DRB5 = Total memory in row0+1+2+3+4+5 (in 8 MB)
+ * 0x66 DRB6 = Total memory in row0+1+2+3+4+5+6 (in 8 MB)
+ * 0x67 DRB7 = Total memory in row0+1+2+3+4+5+6+7 (in 8 MB)
+ */
+ /* Set the DRBs to zero for now, this will be fixed later. */
+ DRB0, 0x00, 0x00,
+ DRB1, 0x00, 0x00,
+ DRB2, 0x00, 0x00,
+ DRB3, 0x00, 0x00,
+ DRB4, 0x00, 0x00,
+ DRB5, 0x00, 0x00,
+ DRB6, 0x00, 0x00,
+ DRB7, 0x00, 0x00,
+
+ /* FDHC - Fixed DRAM Hole Control Register
+ * 0x68
+ *
+ * Controls two fixed DRAM holes: 512 KB - 640 KB and 15 MB - 16 MB.
+ *
+ * [7:6] Hole Enable (HEN)
+ * 00 = None
+ * 01 = 512 KB - 640 KB (128 KB)
+ * 10 = 15 MB - 16 MB (1 MB)
+ * 11 = Reserved
+ * [5:0] Reserved
+ */
+ /* No memory holes. */
+ FDHC, 0x00, 0x00,
+
+ /* RPS - SDRAM Row Page Size Register
+ * 0x74 - 0x75
+ *
+ * Sets the row page size for SDRAM. For EDO memory, the page
+ * size is fixed at 2 KB.
+ *
+ * Bits[1:0] Page Size
+ * 00 2 KB
+ * 01 4 KB
+ * 10 8 KB
+ * 11 Reserved
+ *
+ * RPS bits Corresponding DRB register
+ * [01:00] DRB[0], row 0
+ * [03:02] DRB[1], row 1
+ * [05:04] DRB[2], row 2
+ * [07:06] DRB[3], row 3
+ * [09:08] DRB[4], row 4
+ * [11:10] DRB[5], row 5
+ * [13:12] DRB[6], row 6
+ * [15:14] DRB[7], row 7
+ */
+ /* Power on defaults to 2KB. Will be set later. */
+ // RPS + 0, 0x00, 0x00,
+ // RPS + 1, 0x00, 0x00,
+
+ /* SDRAMC - SDRAM Control Register
+ * 0x76 - 0x77
+ *
+ * [15:10] Reserved
+ * [09:08] Idle/Pipeline DRAM Leadoff Timing (IPDLT)
+ * 00 = Illegal
+ * 01 = Add a clock delay to the lead-off clock count
+ * 1x = Illegal
+ * [07:05] SDRAM Mode Select (SMS)
+ * 000 = Normal SDRAM Operation (default)
+ * 001 = NOP Command Enable
+ * 010 = All Banks Precharge Enable
+ * 011 = Mode Register Set Enable
+ * 100 = CBR Enable
+ * 101 = Reserved
+ * 110 = Reserved
+ * 111 = Reserved
+ * [04:04] SDRAMPWR
+ * 0 = 3 DIMM configuration
+ * 1 = 4 DIMM configuration
+ * [03:03] Leadoff Command Timing (LCT)
+ * 0 = 4 CS# Clock
+ * 1 = 3 CS# Clock
+ * [02:02] CAS# Latency (CL)
+ * 0 = 3 DCLK CAS# latency
+ * 1 = 2 DCLK CAS# latency
+ * [01:01] SDRAM RAS# to CAS# Delay (SRCD)
+ * 0 = 3 clocks between a row activate and a read or write cmd.
+ * 1 = 2 clocks between a row activate and a read or write cmd.
+ * [00:00] SDRAM RAS# Precharge (SRP)
+ * 0 = 3 clocks of RAS# precharge
+ * 1 = 2 clocks of RAS# precharge
+ */
+#if CONFIG_SDRAMPWR_4DIMM
+ SDRAMC + 0, 0x00, 0x10, /* The board has 4 DIMM slots. */
+#else
+ SDRAMC + 0, 0x00, 0x00, /* The board has 3 DIMM slots. */
#endif
+ SDRAMC + 1, 0x00, 0x00,
+
+ /* PGPOL - Paging Policy Register
+ * 0x78 - 0x79
+ *
+ * [15:08] Banks per Row (BPR)
+ * Each bit in this field corresponds to one row of the memory
+ * array. Bit 15 corresponds to row 7 while bit 8 corresponds
+ * to row 0. Bits for empty rows are "don't care".
+ * 0 = 2 banks
+ * 1 = 4 banks
+ * [07:05] Reserved
+ * [04:04] Intel Reserved
+ * [03:00] DRAM Idle Timer (DIT)
+ * 0000 = 0 clocks
+ * 0001 = 2 clocks
+ * 0010 = 4 clocks
+ * 0011 = 8 clocks
+ * 0100 = 10 clocks
+ * 0101 = 12 clocks
+ * 0110 = 16 clocks
+ * 0111 = 32 clocks
+ * 1xxx = Infinite (pages are not closed for idle condition)
+ */
+ PGPOL + 0, 0x00, 0x00,
+ PGPOL + 1, 0x00, 0xff,
+
+ /* PMCR - Power Management Control Register
+ * 0x7a
+ *
+ * [07:07] Power Down SDRAM Enable (PDSE)
+ * 1 = Enable
+ * 0 = Disable
+ * [06:06] ACPI Control Register Enable (SCRE)
+ * 1 = Enable
+ * 0 = Disable (default)
+ * [05:05] Suspend Refresh Type (SRT)
+ * 1 = Self refresh mode
+ * 0 = CBR fresh mode
+ * [04:04] Normal Refresh Enable (NREF_EN)
+ * 1 = Enable
+ * 0 = Disable
+ * [03:03] Quick Start Mode (QSTART)
+ * 1 = Quick start mode for the processor is enabled
+ * [02:02] Gated Clock Enable (GCLKEN)
+ * 1 = Enable
+ * 0 = Disable
+ * [01:01] AGP Disable (AGP_DIS)
+ * 1 = Disable
+ * 0 = Enable
+ * [00:00] CPU reset without PCIRST enable (CRst_En)
+ * 1 = Enable
+ * 0 = Disable
+ */
+ /* Enable normal refresh and the gated clock. */
+ // TODO: Only do this later?
+ // PMCR, 0x00, 0x14,
+ PMCR, 0x00, 0x00,
+
+ /* Enable SCRR.SRRAEN and let BX choose the SRR. */
+ SCRR + 1, 0x00, 0x10,
+};
+
+/*-----------------------------------------------------------------------------
+SDRAM configuration functions.
+-----------------------------------------------------------------------------*/
-void dimms_read(unsigned long x)
+/**
+ * Send the specified RAM command to all DIMMs.
+ *
+ * @param command The RAM command to send to the DIMM(s).
+ */
+static void do_ram_command(u32 command)
{
- uint8_t c;
- unsigned long eax;
- volatile unsigned long y;
- eax = x;
- for(c = 0; c < 6; c++) {
- y = * (volatile unsigned long *) eax;
- eax += 0x10000000;
+ int i, caslatency;
+ u8 dimm_start, dimm_end;
+ u16 reg16;
+ u32 addr, addr_offset;
+
+ /* Configure the RAM command. */
+ reg16 = pci_read_config16(NB, SDRAMC);
+ reg16 &= 0xff1f; /* Clear bits 7-5. */
+ reg16 |= (u16) (command << 5); /* Write command into bits 7-5. */
+ pci_write_config16(NB, SDRAMC, reg16);
+
+ /*
+ * RAM_COMMAND_NORMAL affects only the memory controller and
+ * doesn't need to be "sent" to the DIMMs.
+ */
+ if (command == RAM_COMMAND_NORMAL)
+ return;
+
+ /* Send the RAM command to each row of memory. */
+ dimm_start = 0;
+ for (i = 0; i < (DIMM_SOCKETS * 2); i++) {
+ addr_offset = 0;
+ caslatency = 3; /* TODO: Dynamically get CAS latency later. */
+ if (command == RAM_COMMAND_MRS) {
+ /*
+ * MAA[12:11,9:0] must be inverted when sent to DIMM
+ * 2 or 3 (no inversion if sent to DIMM 0 or 1).
+ */
+ if ((i >= 0 && i <= 3) && caslatency == 3)
+ addr_offset = 0x1d0;
+ if ((i >= 4 && i <= 7) && caslatency == 3)
+ addr_offset = 0x1e28;
+ if ((i >= 0 && i <= 3) && caslatency == 2)
+ addr_offset = 0x150;
+ if ((i >= 4 && i <= 7) && caslatency == 2)
+ addr_offset = 0x1ea8;
+ }
+
+ dimm_end = pci_read_config8(NB, DRB + i);
+
+ addr = (dimm_start * 8 * 1024 * 1024) + addr_offset;
+ if (dimm_end > dimm_start) {
+#if 0
+ PRINT_DEBUG(" Sending RAM command 0x%04x to 0x%08x\n",
+ reg16, addr);
+#endif
+
+ read32(addr);
+ }
+
+ /* Set the start of the next DIMM. */
+ dimm_start = dimm_end;
}
}
-void dimms_write(int x)
+static void set_dram_buffer_strength(void)
{
- uint8_t c;
- unsigned long eax = x;
- for(c = 0; c < 6; c++) {
- *(volatile unsigned long *) eax = 0;
- eax += 0x10000000;
+ /* To give some breathing room for romcc,
+ * mbsc0 doubles as drb
+ * mbsc1 doubles as drb1
+ * mbfs0 doubles as i and reg
+ */
+ uint8_t mbsc0,mbsc1,mbsc3,mbsc4,mbfs0,mbfs2,fsb;
+
+ /* Tally how many rows between rows 0-3 and rows 4-7 are populated.
+ * This determines how to program MBFS and MBSC.
+ */
+ uint8_t dimm03 = 0;
+ uint8_t dimm47 = 0;
+
+ mbsc0 = 0;
+ for (mbfs0 = DRB0; mbfs0 <= DRB7; mbfs0++) {
+ mbsc1 = pci_read_config8(NB, mbfs0);
+ if (mbsc0 != mbsc1) {
+ if (mbfs0 <= DRB3) {
+ dimm03++;
+ } else {
+ dimm47++;
+ }
+ mbsc0 = mbsc1;
+ }
}
-}
+ /* Algorithm bitmap for programming MBSC[39:0] and MBFS[23:0].
+ *
+ * The 440BX datasheet says buffer frequency is independent from bus
+ * frequency and mismatch both ways are possible. This is how it is
+ * programmed in the ASUS P2B-LS mainboard.
+ *
+ * There are four main conditions to check when programming DRAM buffer
+ * frequency and strength:
+ *
+ * a: >2 rows populated across DIMM0,1
+ * b: >2 rows populated across DIMM2,3
+ * c: >4 rows populated across all DIMM slots
+ * and either one of:
+ * 1: NBXCFG[13] strapped as 100MHz, or
+ * 6: NBXCFG[13] strapped as 66MHz
+ *
+ * CKE0/FENA ----------------------------------------------------------+
+ * CKE1/GCKE -------------------[ MBFS ]------------------------+|
+ * DQMA/CASA[764320]# ----------[ 0 = 66MHz ]-----------------------+||
+ * DQMB1/CASB1# ----------------[ 1 = 100MHz ]----------------------+|||
+ * DQMB5/CASB5# ---------------------------------------------------+||||
+ * DQMA1/CASA1# --------------------------------------------------+|||||
+ * DQMA5/CASA5# -------------------------------------------------+||||||
+ * CSA0-5#,CSB0-5# ----------------------------------------++++++|||||||
+ * CSA6#/CKE2# -------------------------------------------+|||||||||||||
+ * CSB6#/CKE4# ------------------------------------------+||||||||||||||
+ * CSA7#/CKE3# -----------------------------------------+|||||||||||||||
+ * CSB7#/CKE5# ----------------------------------------+||||||||||||||||
+ * MECC[7:0] #2/#1 (100MHz) -------------------------++|||||||||||||||||
+ * MD[63:0] #2/#1 (100MHz) ------------------------++|||||||||||||||||||
+ * MAB[12:11,9:0]#,MAB[13,10],WEB#,SRASB#,SCASB# -+|||||||||||||||||||||
+ * MAA[13:0],WEA#,SRASA#,SCASA# -----------------+||||||||||||||||||||||
+ * Reserved ------------------------------------+|||||||||||||||||||||||
+ * ||||||||||||||||||||||||
+ * 3 32 21 10 0 * 2 21 10 0
+ * 9876543210987654321098765432109876543210 * 321098765432109876543210
+ * a 10------------------------1010---------- * -1---------------11----- a
+ *!a 11------------------------1111---------- * -0---------------00----- !a
+ * b --10--------------------------1010------ * --1----------------11--- b
+ *!b --11--------------------------1111------ * --0----------------00--- !b
+ * c ----------------------------------1100-- * ----------------------1- c
+ *!c ----------------------------------1011-- * ----------------------0- !c
+ * 1 ----1010101000000000000000------------00 * ---11111111111111----1-0 1
+ * 6 ----000000000000000000000010101010----00 * ---1111111111111100000-0 6
+ * | | | | | | | | | | ||||||| | | | | | |
+ * | | | | | | | | | | ||||||| | | | | | +- CKE0/FENA
+ * | | | | | | | | | | ||||||| | | | | +--- CKE1/GCKE
+ * | | | | | | | | | | ||||||| | | | +----- DQMA/CASA[764320]#
+ * | | | | | | | | | | ||||||| | | +------- DQMB1/CASB1#
+ * | | | | | | | | | | ||||||| | +--------- DQMB5/CASB5#
+ * | | | | | | | | | | ||||||| +----------- DQMA1/CASA1#
+ * | | | | | | | | | | ||||||+------------- DQMA5/CASA5#
+ * | | | | | | | | | | ++++++-------------- CSA0-5#,CSB0-5# [ 0=1x;1=2x ]
+ * | | | | | | | | | +--------------------- CSA6#/CKE2#
+ * | | | | | | | | +---[ MBSC ]------ CSB6#/CKE4#
+ * | | | | | | | +-----[ 00 = 1x ]------ CSA7#/CKE3#
+ * | | | | | | +-------[ 01 invalid ]------ CSB7#/CKE5#
+ * | | | | | +---------[ 10 = 2x ]------ MECC[7:0] #1 (2x)
+ * | | | | +-----------[ 11 = 3x ]------ MECC[7:0] #2 (2x)
+ * | | | +--------------------------------- MD[63:0] #1 (2x)
+ * | | +----------------------------------- MD[63:0] #2 (2x)
+ * | +------------------------------------- MAB[12:11,9:0]#,MAB[13,10],WEB#,SRASB#,SCASB#
+ * +--------------------------------------- MAA[13:0],WEA#,SRASA#,SCASA#
+ * MBSC[47:40] and MBFS[23] are reserved.
+ *
+ * This algorithm is checked against the ASUS P2B-LS (which has
+ * 4 DIMM slots) factory BIOS.
+ * Therefore it assumes a board with 4 slots, and will need testing
+ * on boards with 3 DIMM slots.
+ */
+ mbsc0 = 0x80;
+ mbsc1 = 0x2a;
+ mbfs2 = 0x1f;
+ if (pci_read_config8(NB, NBXCFG + 1) & 0x30) {
+ fsb = 66;
+ mbsc3 = 0x00;
+ mbsc4 = 0x00;
+ mbfs0 = 0x80;
+ } else {
+ fsb = 100;
+ mbsc3 = 0xa0;
+ mbsc4 = 0x0a;
+ mbfs0 = 0x84;
+ }
-#ifdef DEBUG_SETNORTHB
-void setnorthb(device_t north, uint8_t reg, uint8_t val)
-{
- print_debug("setnorth: reg ");
- print_debug_hex8(reg);
- print_debug(" to ");
- print_debug_hex8(val);
- print_debug("\r\n");
- pci_write_config8(north, reg, val);
+ if (dimm03 > 2) {
+ mbsc4 = mbsc4 | 0x80;
+ mbsc1 = mbsc1 | 0x28;
+ mbfs2 = mbfs2 | 0x40;
+ mbfs0 = mbfs0 | 0x60;
+ } else {
+ mbsc4 = mbsc4 | 0xc0;
+ if (fsb == 100) {
+ mbsc1 = mbsc1 | 0x3c;
+ }
+ }
+ if (dimm47 > 2) {
+ mbsc4 = mbsc4 | 0x20;
+ mbsc1 = mbsc1 | 0x02;
+ mbsc0 = mbsc0 | 0x80;
+ mbfs2 = mbfs2 | 0x20;
+ mbfs0 = mbfs0 | 0x18;
+ } else {
+ mbsc4 = mbsc4 | 0x30;
+ if (fsb == 100) {
+ mbsc1 = mbsc1 | 0x03;
+ mbsc0 = mbsc0 | 0xc0;
+ }
+ }
+ if ((dimm03 + dimm47) > 4) {
+ mbsc0 = mbsc0 | 0x30;
+ mbfs0 = mbfs0 | 0x02;
+ } else {
+ mbsc0 = mbsc0 | 0x2c;
+ }
+
+ pci_write_config8(NB, MBSC + 0, mbsc0);
+ pci_write_config8(NB, MBSC + 1, mbsc1);
+ pci_write_config8(NB, MBSC + 2, 0x00);
+ pci_write_config8(NB, MBSC + 3, mbsc3);
+ pci_write_config8(NB, MBSC + 4, mbsc4);
+ pci_write_config8(NB, MBFS + 0, mbfs0);
+ pci_write_config8(NB, MBFS + 1, 0xff);
+ pci_write_config8(NB, MBFS + 2, mbfs2);
}
-#else
-#define setnorthb pci_write_config8
-#endif
-void
-dumpnorth(device_t north)
+/*-----------------------------------------------------------------------------
+DIMM-independant configuration functions.
+-----------------------------------------------------------------------------*/
+
+static void spd_enable_refresh(void)
{
- unsigned int r, c;
- for(r = 0; ; r += 16) {
- print_debug_hex8(r);
- print_debug(":");
- for(c = 0; c < 16; c++) {
- print_debug_hex8(pci_read_config8(north, r+c));
- print_debug(" ");
- }
- print_debug("\r\n");
- if (r >= 240)
- break;
- }
+ int i, value;
+ uint8_t reg;
+
+ reg = pci_read_config8(NB, DRAMC);
+
+ for (i = 0; i < DIMM_SOCKETS; i++) {
+ value = spd_read_byte(DIMM0 + i, SPD_REFRESH);
+ if (value < 0)
+ continue;
+ reg = (reg & 0xf8) | refresh_rate_map[(value & 0x7f)];
+
+ PRINT_DEBUG(" Enabling refresh (DRAMC = 0x%02x) for DIMM %02x\n", reg, i);
+ }
+
+ pci_write_config8(NB, DRAMC, reg);
}
-static void sdram_set_registers(const struct mem_controller *ctrl)
+/*-----------------------------------------------------------------------------
+Public interface.
+-----------------------------------------------------------------------------*/
+
+void sdram_set_registers(void)
{
- device_t north = (device_t) 0;
- uint8_t c, r;
-
- print_err("vt8601 init starting\r\n");
- north = pci_locate_device(PCI_ID(0x1106, 0x8601), 0);
- north = 0;
- print_debug_hex32(north);
- print_debug(" is the north\n");
- print_debug_hex16(pci_read_config16(north, 0));
- print_debug(" ");
- print_debug_hex16(pci_read_config16(north, 2));
- print_debug("\r\n");
-
- /* All we are doing now is setting initial known-good values that will
- * be revised later as we read SPD
- */
- // memory clk enable. We are not using ECC
- pci_write_config8(north,0x78, 0x01);
- print_debug_hex8(pci_read_config8(north, 0x78));
- // dram control, see the book.
-#if DIMM_PC133
- pci_write_config8(north,0x68, 0x52);
-#else
- pci_write_config8(north,0x68, 0x42);
-#endif
- // dram control, see the book.
- pci_write_config8(north,0x6B, 0x0c);
- // Initial setting, 256MB in each bank, will be rewritten later.
- pci_write_config8(north,0x5A, 0x20);
- print_debug_hex8(pci_read_config8(north, 0x5a));
- pci_write_config8(north,0x5B, 0x40);
- pci_write_config8(north,0x5C, 0x60);
- pci_write_config8(north,0x5D, 0x80);
- pci_write_config8(north,0x5E, 0xA0);
- pci_write_config8(north,0x5F, 0xC0);
- // It seems we have to take care of these 2 registers as if
- // they are bank 6 and 7.
- pci_write_config8(north,0x56, 0xC0);
- pci_write_config8(north,0x57, 0xC0);
-
- // SDRAM in all banks
- pci_write_config8(north,0x60, 0x3F);
- // DRAM timing. I'm suspicious of this
- // This is for all banks, 64 is 0,1. 65 is 2,3. 66 is 4,5.
- // ras precharge 4T, RAS pulse 5T
- // cas2 is 0xd6, cas3 is 0xe6
- // we're also backing off write pulse width to 2T, so result is 0xee
-#if DIMM_CL2
- pci_write_config8(north,0x64, 0xd4);
- pci_write_config8(north,0x65, 0xd4);
- pci_write_config8(north,0x66, 0xd4);
-#else // CL=3
- pci_write_config8(north,0x64, 0xe4);
- pci_write_config8(north,0x65, 0xe4);
- pci_write_config8(north,0x66, 0xe4);
-#endif
+ int i, max;
+ uint8_t reg;
- // dram frequency select.
- // enable 4K pages for 64M dram.
-#if DIMM_PC133
- pci_write_config8(north,0x69, 0x3c);
-#else
- pci_write_config8(north,0x69, 0xac);
-#endif
+ PRINT_DEBUG("Northbridge prior to SDRAM init:\n");
+ DUMPNORTH();
+
+ max = ARRAY_SIZE(register_values);
- /* IMPORTANT -- disable refresh counter */
- // refresh counter, disabled.
- pci_write_config8(north,0x6A, 0x00);
-
-
- // clkenable configuration. kevinh FIXME - add precharge
- pci_write_config8(north,0x6C, 0x00);
- // dram read latch delay of 1 ns, MD drive 8 mA,
- // high drive strength on MA[2: 13], we#, cas#, ras#
- // As per Cindy Lee, set to 0x37, not 0x57
- pci_write_config8(north,0x6D, 0x7f);
+ /* Set registers as specified in the register_values[] array. */
+ for (i = 0; i < max; i += 3) {
+ reg = pci_read_config8(NB, register_values[i]);
+ reg &= register_values[i + 1];
+ reg |= register_values[i + 2] & ~(register_values[i + 1]);
+ pci_write_config8(NB, register_values[i], reg);
+#if 0
+ PRINT_DEBUG(" Set register 0x%02x to 0x%02x\n",
+ register_values[i], reg);
+#endif
+ }
}
-/* slot is the dram slot. Return size of side0 in lower 16-bit,
- * side1 in upper 16-bit, in units of 8MB */
-static unsigned long
-spd_module_size(unsigned char slot)
-{
- /* for all the DRAMS, see if they are there and get the size of each
- * module. This is just a very early first cut at sizing.
+struct dimm_size {
+ u32 side1;
+ u32 side2;
+};
+
+static struct dimm_size spd_get_dimm_size(unsigned int device)
+{
+ struct dimm_size sz;
+ int i, module_density, dimm_banks;
+ sz.side1 = 0;
+ module_density = spd_read_byte(device, SPD_DENSITY_OF_EACH_ROW_ON_MODULE);
+ dimm_banks = spd_read_byte(device, SPD_NUM_DIMM_BANKS);
+
+ /* Find the size of side1. */
+ /* Find the larger value. The larger value is always side1. */
+ for (i = 512; i >= 0; i >>= 1) {
+ if ((module_density & i) == i) {
+ sz.side1 = i;
+ break;
+ }
+ }
+
+ /* Set to 0 in case it's single sided. */
+ sz.side2 = 0;
+
+ /* Test if it's a dual-sided DIMM. */
+ if (dimm_banks > 1) {
+ /* Test if there's a second value. If so it's asymmetrical. */
+ if (module_density != i) {
+ /*
+ * Find second value, picking up where we left off.
+ * i >>= 1 done initially to make sure we don't get
+ * the same value again.
+ */
+ for (i >>= 1; i >= 0; i >>= 1) {
+ if (module_density == (sz.side1 | i)) {
+ sz.side2 = i;
+ break;
+ }
+ }
+ /* If not, it's symmetrical. */
+ } else {
+ sz.side2 = sz.side1;
+ }
+ }
+
+ /*
+ * SPD byte 31 is the memory size divided by 4 so we
+ * need to muliply by 4 to get the total size.
*/
- /* we may run out of registers ... */
- unsigned int banks, rows, cols, reg;
- unsigned int value = 0;
- /* unsigned int module = ((0x50 + slot) << 1) + 1; */
- unsigned int module = 0x50 + slot;
- /* is the module there? if byte 2 is not 4, then we'll assume it
- * is useless.
+ sz.side1 *= 4;
+ sz.side2 *= 4;
+
+ /* It is possible to partially use larger then supported
+ * modules by setting them to a supported size.
*/
- print_info("Slot ");
- print_info_hex8(slot);
- if (smbus_read_byte(module, 2) != 4) {
- print_info(" is empty\r\n");
- return 0;
- }
- print_info(" is SDRAM ");
-
- banks = smbus_read_byte(module, 17);
- /* we're going to assume symmetric banks. Sorry. */
- cols = smbus_read_byte(module, 4) & 0xf;
- rows = smbus_read_byte(module, 3) & 0xf;
- /* grand total. You have rows+cols addressing, * times of banks, times
- * width of data in bytes */
- /* Width is assumed to be 64 bits == 8 bytes */
- value = (1 << (cols + rows)) * banks * 8;
- print_info_hex32(value);
- print_info(" bytes ");
- /* Return in 8MB units */
- value >>= 23;
-
- /* We should have single or double side */
- if (smbus_read_byte(module, 5) == 2) {
- print_info("x2");
- value = (value << 16) | value;
+ if(sz.side1 > 128) {
+ PRINT_DEBUG("Side1 was %dMB but only 128MB will be used.\n",
+ sz.side1);
+ sz.side1 = 128;
+
+ if(sz.side2 > 128) {
+ PRINT_DEBUG("Side2 was %dMB but only 128MB will be used.\n",
+ sz.side2);
+ sz.side2 = 128;
+ }
}
- print_info("\r\n");
- return value;
+ return sz;
}
+/*
+ * Sets DRAM attributes one DIMM at a time, based on SPD data.
+ * Northbridge settings that are set: NBXCFG[31:24], DRB0-DRB7, RPS, DRAMC.
+ */
+static void set_dram_row_attributes(void)
+{
+ int i, dra, drb, col, width, value, rps;
+ u8 bpr; /* Top 8 bits of PGPOL */
+ u8 nbxecc = 0; /* NBXCFG[31:24] */
+ u8 edo, sd, regsd; /* EDO, SDRAM, registered SDRAM */
-static int
-spd_num_chips(unsigned char slot)
-{
-/* unsigned int module = ((0x50 + slot) << 1) + 1; */
- unsigned int module = 0x50 + slot;
- unsigned int width;
-
- width = smbus_read_byte(module, 13);
- if (width == 0)
- width = 8;
- return 64 / width;
-}
+ edo = 0;
+ sd = 0;
+ regsd = 1;
+ rps = 0;
+ drb = 0;
+ bpr = 0;
-static void sdram_set_spd_registers(const struct mem_controller *ctrl)
-{
-#define T133 7
- unsigned char Trp = 1, Tras = 1, casl = 2, val;
- unsigned char timing = 0xe4;
- /* read Trp */
- val = smbus_read_byte(0x50, 27);
- if (val < 2*T133)
- Trp = 1;
- val = smbus_read_byte(0x50, 30);
- if (val < 5*T133)
- Tras = 0;
- val = smbus_read_byte(0x50, 18);
- if (val < 8)
- casl = 1;
- if (val < 4)
- casl = 0;
-
- val = (Trp << 7) | (Tras << 6) | (casl << 4) | 4;
-
- print_debug_hex8(val); print_debug(" is the computed timing\n");
- /* don't set it. Experience shows that this screwy chipset should just
- * be run with the most conservative timing.
- * pci_write_config8(0, 0x64, val);
- */
+ for (i = 0; i < DIMM_SOCKETS; i++) {
+ unsigned int device;
+ device = DIMM0 + i;
+ bpr >>= 2;
+ nbxecc >>= 2;
+
+ /* First check if a DIMM is actually present. */
+ value = spd_read_byte(device, SPD_MEMORY_TYPE);
+ /* This is 440BX! We do EDO too! */
+ if (value == SPD_MEMORY_TYPE_EDO
+ || value == SPD_MEMORY_TYPE_SDRAM) {
+
+ if (value == SPD_MEMORY_TYPE_EDO) {
+ edo = 1;
+ } else if (value == SPD_MEMORY_TYPE_SDRAM) {
+ sd = 1;
+ }
+ PRINT_DEBUG("Found DIMM in slot %d\n", i);
+
+ if (edo && sd) {
+ print_err("Mixing EDO/SDRAM unsupported!\n");
+ die("HALT\n");
+ }
+
+ /* "DRA" is our RPS for the two rows on this DIMM. */
+ dra = 0;
+
+ /* Columns */
+ col = spd_read_byte(device, SPD_NUM_COLUMNS);
+
+ /*
+ * Is this an ECC DIMM? Actually will be a 2 if so.
+ * TODO: Other register than NBXCFG also needs this
+ * ECC information.
+ */
+ value = spd_read_byte(device, SPD_DIMM_CONFIG_TYPE);
+
+ /* Data width */
+ width = spd_read_byte(device, SPD_MODULE_DATA_WIDTH_LSB);
+
+ /* Exclude error checking data width from page size calculations */
+ if (value) {
+ value = spd_read_byte(device,
+ SPD_ERROR_CHECKING_SDRAM_WIDTH);
+ width -= value;
+ /* ### ECC */
+ /* Clear top 2 bits to help set up NBXCFG. */
+ nbxecc &= 0x3f;
+ } else {
+ /* Without ECC, top 2 bits should be 11. */
+ nbxecc |= 0xc0;
+ }
+
+ /* If any installed DIMM is *not* registered, this system cannot be
+ * configured for registered SDRAM.
+ * By registered, only the address and control lines need to be, which
+ * we can tell by reading SPD byte 21, bit 1.
+ */
+ value = spd_read_byte(device, SPD_MODULE_ATTRIBUTES);
+
+ PRINT_DEBUG("DIMM is ");
+ if ((value & MODULE_REGISTERED) == 0) {
+ regsd = 0;
+ PRINT_DEBUG("not ");
+ }
+ PRINT_DEBUG("registered\n");
+
+ /* Calculate page size in bits. */
+ value = ((1 << col) * width);
+
+ /* Convert to KB. */
+ dra = (value >> 13);
+
+ /* Number of banks of DIMM (single or double sided). */
+ value = spd_read_byte(device, SPD_NUM_DIMM_BANKS);
+
+ /* Once we have dra, col is done and can be reused.
+ * So it's reused for number of banks.
+ */
+ col = spd_read_byte(device, SPD_NUM_BANKS_PER_SDRAM);
+
+ if (value == 1) {
+ /*
+ * Second bank of 1-bank DIMMs "doesn't have
+ * ECC" - or anything.
+ */
+ if (dra == 2) {
+ dra = 0x0; /* 2KB */
+ } else if (dra == 4) {
+ dra = 0x1; /* 4KB */
+ } else if (dra == 8) {
+ dra = 0x2; /* 8KB */
+ } else if (dra >= 16) {
+ /* Page sizes larger than supported are
+ * set to 8KB to use module partially.
+ */
+ PRINT_DEBUG("Page size forced to 8KB.\n");
+ dra = 0x2; /* 8KB */
+ } else {
+ dra = -1;
+ }
+ /*
+ * Sets a flag in PGPOL[BPR] if this DIMM has
+ * 4 banks per row.
+ */
+ if (col == 4)
+ bpr |= 0x40;
+ } else if (value == 2) {
+ if (dra == 2) {
+ dra = 0x0; /* 2KB */
+ } else if (dra == 4) {
+ dra = 0x05; /* 4KB */
+ } else if (dra == 8) {
+ dra = 0x0a; /* 8KB */
+ } else if (dra >= 16) {
+ /* Ditto */
+ PRINT_DEBUG("Page size forced to 8KB.\n");
+ dra = 0x0a; /* 8KB */
+ } else {
+ dra = -1;
+ }
+ /* Ditto */
+ if (col == 4)
+ bpr |= 0xc0;
+ } else {
+ print_err("# of banks of DIMM unsupported!\n");
+ die("HALT\n");
+ }
+ if (dra == -1) {
+ print_err("Page size not supported\n");
+ die("HALT\n");
+ }
+
+ /*
+ * 440BX supports asymmetrical dual-sided DIMMs,
+ * but can't handle DIMMs smaller than 8MB per
+ * side.
+ */
+ struct dimm_size sz = spd_get_dimm_size(device);
+ if ((sz.side1 < 8)) {
+ print_err("DIMMs smaller than 8MB per side\n"
+ "are not supported on this NB.\n");
+ die("HALT\n");
+ }
+
+ /* Divide size by 8 to set up the DRB registers. */
+ drb += (sz.side1 / 8);
+
+ /*
+ * Build the DRB for the next row in MSB so it gets
+ * placed in DRB[n+1] where it belongs when written
+ * as a 16-bit word.
+ */
+ drb &= 0xff;
+ drb |= (drb + (sz.side2 / 8)) << 8;
+ } else {
+#if 0
+ PRINT_DEBUG("No DIMM found in slot %d\n", i);
+#endif
+
+ /* If there's no DIMM in the slot, set dra to 0x00. */
+ dra = 0x00;
+ /* Still have to propagate DRB over. */
+ drb &= 0xff;
+ drb |= (drb << 8);
+ }
+
+ pci_write_config16(NB, DRB + (2 * i), drb);
+#if 0
+ PRINT_DEBUG("DRB has been set to 0x%04x\n", drb);
+#endif
+
+ /* Brings the upper DRB back down to be base for
+ * DRB calculations for the next two rows.
+ */
+ drb >>= 8;
+
+ rps |= (dra & 0x0f) << (i * 4);
+ }
+
+ /* Set paging policy register. */
+ pci_write_config8(NB, PGPOL + 1, bpr);
+ PRINT_DEBUG("PGPOL[BPR] has been set to 0x%02x\n", bpr);
+
+ /* Set DRAM row page size register. */
+ pci_write_config16(NB, RPS, rps);
+ PRINT_DEBUG("RPS has been set to 0x%04x\n", rps);
+
+ /* ### ECC */
+ pci_write_config8(NB, NBXCFG + 3, nbxecc);
+ PRINT_DEBUG("NBXECC[31:24] has been set to 0x%02x\n", nbxecc);
+
+ /* Set DRAMC[4:3] to proper memory type (EDO/SDRAM/Registered SDRAM). */
+
+ /* i will be used to set DRAMC[4:3]. */
+ if (regsd && sd) {
+ i = 0x10; // Registered SDRAM
+ } else if (sd) {
+ i = 0x08; // SDRAM
+ } else {
+ i = 0; // EDO
+ }
+
+ value = pci_read_config8(NB, DRAMC) & 0xe7;
+ value |= i;
+ pci_write_config8(NB, DRAMC, value);
+ PRINT_DEBUG("DRAMC has been set to 0x%02x\n", value);
}
-static void set_ma_mapping(device_t north, int slot, int type)
+void sdram_set_spd_registers(void)
{
- unsigned char reg, val;
- int shift;
-
- reg = 0x58 + slot/2;
- if (slot%2 >= 1)
- shift = 0;
- else
- shift = 4;
-
- val = pci_read_config8(north, reg);
- val &= ~(0xf << shift);
- val |= type << shift;
- pci_write_config8(north, reg, val);
-}
+ /* Setup DRAM row boundary registers and other attributes. */
+ set_dram_row_attributes();
+
+ /* Setup DRAM buffer strength. */
+ set_dram_buffer_strength();
+ /* TODO: Set PMCR? */
+ // pci_write_config8(NB, PMCR, 0x14);
+ pci_write_config8(NB, PMCR, 0x10);
+
+ /* TODO: This is for EDO memory only. */
+ pci_write_config8(NB, DRAMT, 0x03);
+}
-static void sdram_enable(int controllers, const struct mem_controller *ctrl)
+void sdram_enable(void)
{
- unsigned char i;
- static const uint8_t ramregs[] = {
- 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x56, 0x57
- };
- device_t north = 0;
- uint32_t size, base, slot, ma;
- /* begin to initialize*/
- // I forget why we need this, but we do
- dimms_write(0xa55a5aa5);
-
- /* set NOP*/
- pci_write_config8(north,0x6C, 0x01);
- print_debug("NOP\r\n");
- /* wait 200us*/
- // You need to do the memory reference. That causes the nop cycle.
- dimms_read(0);
- udelay(400);
- print_debug("PRECHARGE\r\n");
- /* set precharge */
- pci_write_config8(north,0x6C, 0x02);
- print_debug("DUMMY READS\r\n");
- /* dummy reads*/
- dimms_read(0);
- udelay(200);
- print_debug("CBR\r\n");
- /* set CBR*/
- pci_write_config8(north,0x6C, 0x04);
-
- /* do 8 reads and wait >100us between each - from via*/
- dimms_read(0);
- udelay(200);
- dimms_read(0);
- udelay(200);
- dimms_read(0);
- udelay(200);
- dimms_read(0);
- udelay(200);
- dimms_read(0);
- udelay(200);
- dimms_read(0);
- udelay(200);
- dimms_read(0);
- udelay(200);
- dimms_read(0);
- udelay(200);
- print_debug("MRS\r\n");
- /* set MRS*/
- pci_write_config8(north,0x6c, 0x03);
-#if DIMM_CL2
- dimms_read(0x150);
-#else // CL=3
- dimms_read(0x1d0);
-#endif
+ int i;
+
+ /* 0. Wait until power/voltages and clocks are stable (200us). */
udelay(200);
- print_debug("NORMAL\r\n");
- /* set to normal mode */
- pci_write_config8(north,0x6C, 0x08);
-
- dimms_write(0x55aa55aa);
- dimms_read(0);
+
+ /* 1. Apply NOP. Wait 200 clock cycles (200us should do). */
+ PRINT_DEBUG("RAM Enable 1: Apply NOP\n");
+ do_ram_command(RAM_COMMAND_NOP);
udelay(200);
- print_debug("set ref. rate\r\n");
- // Set the refresh rate.
-#if DIMM_PC133
- pci_write_config8(north,0x6A, 0x86);
-#else
- pci_write_config8(north,0x6A, 0x65);
-#endif
- print_debug("enable multi-page open\r\n");
- // enable multi-page open
- pci_write_config8(north,0x6B, 0x0d);
-
- base = 0;
- for(slot = 0; slot < 4; slot++) {
- size = spd_module_size(slot);
- /* side 0 */
- base += size & 0xffff;
- pci_write_config8(north, ramregs[2*slot], base);
- /* side 1 */
- base += size >> 16;
- if (base > 0xff)
- base = 0xff;
- pci_write_config8(north, ramregs[2*slot + 1], base);
-
- if (!size)
- continue;
- /* Calculate the value of MA mapping type register,
- * based on size of SDRAM chips. */
- size = (size & 0xffff) << (3 + 3);
- /* convert module size to be in Mbits */
- size /= spd_num_chips(slot);
- print_debug_hex16(size);
- print_debug(" is the chip size\r\n");
- if (size < 64)
- ma = 0;
- if (size < 256)
- ma = 8;
- else
- ma = 0xe;
- print_debug_hex16(ma);
- print_debug(" is the MA type\r\n");
- set_ma_mapping(north, slot, ma);
+ /* 2. Precharge all. Wait tRP. */
+ PRINT_DEBUG("RAM Enable 2: Precharge all\n");
+ do_ram_command(RAM_COMMAND_PRECHARGE);
+ udelay(1);
+
+ /* 3. Perform 8 refresh cycles. Wait tRC each time. */
+ PRINT_DEBUG("RAM Enable 3: CBR\n");
+ for (i = 0; i < 8; i++) {
+ do_ram_command(RAM_COMMAND_CBR);
+ udelay(1);
}
- print_err("vt8601 done\r\n");
+
+ /* 4. Mode register set. Wait two memory cycles. */
+ PRINT_DEBUG("RAM Enable 4: Mode register set\n");
+ do_ram_command(RAM_COMMAND_MRS);
+ udelay(2);
+
+ /* 5. Normal operation. */
+ PRINT_DEBUG("RAM Enable 5: Normal operation\n");
+ do_ram_command(RAM_COMMAND_NORMAL);
+ udelay(1);
+
+ /* 6. Finally enable refresh. */
+ PRINT_DEBUG("RAM Enable 6: Enable refresh\n");
+ // pci_write_config8(NB, PMCR, 0x10);
+ spd_enable_refresh();
+ udelay(1);
+
+ PRINT_DEBUG("Northbridge following SDRAM init:\n");
+ DUMPNORTH();
}