diff options
author | Stefan Reinauer <stepan@coresystems.de> | 2009-04-17 08:37:18 +0000 |
---|---|---|
committer | Stefan Reinauer <stepan@openbios.org> | 2009-04-17 08:37:18 +0000 |
commit | aeba92ab5b0afd1464d6b1a275b5f5b00b351b32 (patch) | |
tree | 225fbff67fc05e70507ac6ef7b3af32f00bac6f8 /src/northbridge/via/cx700/raminit.c | |
parent | 56c51bd120a935e64cfd96d8ad71c9d1f7aab323 (diff) |
Add VIA CX700 support, plus VIA vt8454c reference board support.
Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4126 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge/via/cx700/raminit.c')
-rw-r--r-- | src/northbridge/via/cx700/raminit.c | 1480 |
1 files changed, 1480 insertions, 0 deletions
diff --git a/src/northbridge/via/cx700/raminit.c b/src/northbridge/via/cx700/raminit.c new file mode 100644 index 0000000000..ff21e537ca --- /dev/null +++ b/src/northbridge/via/cx700/raminit.c @@ -0,0 +1,1480 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2009 coresystems GmbH + * + * 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 + */ + +#include <types.h> +#include <spd.h> +#include <spd_ddr2.h> +#include <sdram_mode.h> +#include <delay.h> +#include "cx700_registers.h" + +// #define DEBUG_RAM_SETUP 1 + +/* Debugging macros. */ +#if defined(DEBUG_RAM_SETUP) +#define PRINTK_DEBUG(x...) printk_debug(x) +#else +#define PRINTK_DEBUG(x...) +#endif + +#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 + +#define HOSTCTRL PCI_DEV(0, 0, 2) +#define MEMCTRL PCI_DEV(0, 0, 3) + +#define DDRII_666 0x5 +#define DDRII_533 0x4 +#define DDRII_400 0x3 +#define DDRII_333 0x2 +#define DDRII_266 0x1 +#define DDRII_200 0x0 + +#define OHM_150 1 + +#ifdef MEM_WIDTH_32BIT_MODE +#define SDRAM1X_RA_14 30 +#define SDRAM1X_RA_13 29 +#define SDRAM1X_RA_12 28 +#define SDRAM1X_RA_12_8bk 26 +#define SDRAM1X_CA_12 15 +#define SDRAM1X_CA_11 14 +#define SDRAM1X_CA_09 11 +#define SDRAM1X_CA_09_8bk 11 +#define SDRAM1X_BA1 13 +#define SDRAM1X_BA2_8bk 14 +#define SDRAM1X_BA1_8bk 13 +#else +#define SDRAM1X_RA_14 31 +#define SDRAM1X_RA_13 30 +#define SDRAM1X_RA_12 29 +#define SDRAM1X_RA_12_8bk 27 +#define SDRAM1X_CA_12 16 +#define SDRAM1X_CA_11 15 +#define SDRAM1X_CA_09 12 +#define SDRAM1X_CA_09_8bk 12 +#define SDRAM1X_BA1 14 +#define SDRAM1X_BA2_8bk 15 +#define SDRAM1X_BA1_8bk 14 +#endif + +#define MA_Column 0x06 +#define MA_Bank 0x08 +#define MA_Row 0x30 +#define MA_4_Bank 0x00 +#define MA_8_Bank 0x08 +#define MA_12_Row 0x00 +#define MA_13_Row 0x10 +#define MA_14_Row 0x20 +#define MA_15_Row 0x30 +#define MA_9_Column 0x00 +#define MA_10_Column 0x02 +#define MA_11_Column 0x04 +#define MA_12_Column 0x06 + +#define GET_SPD(i, val, tmp, reg) \ + do{ \ + val = 0; \ + tmp = 0; \ + for(i = 0; i < 2; i++) { \ + if(pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_REG_BASE + (i << 1)))) { \ + tmp = get_spd_data(ctrl, i, reg); \ + if(tmp > val) \ + val = tmp; \ + } \ + } \ + } while ( 0 ) + +#define REGISTERPRESET(bus,dev,fun,bdfspec) \ + { u8 i, reg; \ + for (i=0; i<(sizeof((bdfspec))/sizeof(struct regmask)); i++) { \ + printk_debug("Writing bus " #bus " dev " #dev " fun " #fun " register "); \ + printk_debug("%02x", (bdfspec)[i].reg); \ + printk_debug("\n"); \ + reg = pci_read_config8(PCI_DEV((bus), (dev), (fun)), (bdfspec)[i].reg); \ + reg &= (bdfspec)[i].mask; \ + reg |= (bdfspec)[i].val; \ + pci_write_config8(PCI_DEV((bus), (dev), (fun)), (bdfspec)[i].reg, reg); \ + } \ + } + + +static void do_ram_command(const struct mem_controller *ctrl, u8 command) +{ + u8 reg; + + reg = pci_read_config8(MEMCTRL, 0x6b); + reg &= 0xf8; /* Clear bits 2-0. */ + reg |= command; + pci_write_config8(MEMCTRL, 0x6b, reg); + + PRINTK_DEBUG(" Sending RAM command 0x%02x\n", reg); +} + +// TODO factor out to another file +static void c7_cpu_setup(const struct mem_controller *ctrl) +{ + u8 size, i; + size = sizeof(Reg_Val) / sizeof(Reg_Val[0]); + for (i = 0; i < size; i += 2) + pci_write_config8(HOSTCTRL, Reg_Val[i], Reg_Val[i + 1]); +} + +static void ddr_detect(const struct mem_controller *ctrl) +{ + /* FIXME: Only supports 2 ranks per DIMM */ + u8 val, rsize, dimm; + u8 nrank = 0; + u8 ndimm = 0; + u8 rmap = 0; + for (dimm = 0; dimm < DIMM_SOCKETS; dimm++) { + val = get_spd_data(ctrl, dimm, 0); + if ((val == 0x80) || (val == 0xff)) { + ndimm++; + rsize = get_spd_data(ctrl, dimm, SPD_RANK_SIZE); + /* unit is 128M */ + rsize = (rsize << 3) | (rsize >> 5); + val = + get_spd_data(ctrl, dimm, + SPD_MOD_ATTRIB_RANK) & SPD_MOD_ATTRIB_RANK_NUM_MASK; + switch (val) { + case 1: + pci_write_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_1 + (dimm << 1)), + rsize); + rmap |= (1 << ((dimm << 1) + 1)); + nrank++; + case 0: + pci_write_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + (dimm << 1)), + rsize); + rmap |= (1 << (dimm << 1)); + nrank++; + } + } + } + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_DIMM_NUM, ndimm); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM, nrank); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_MAP, rmap); +} + +static void sdram_set_safe_values(const struct mem_controller *ctrl) +{ + /* The purpose of this function is to set initial values for the dram + * size and timings. It will be replaced with the SPD based function + * once the RAM commands are working with these values. + */ + u8 regs, val, t, dimm; + u32 spds, tmp; + + regs = pci_read_config8(MEMCTRL, 0x6c); + if (regs & (1 << 6)) + printk_debug("DDR2 Detected.\n"); + else + die("ERROR: DDR1 memory detected but not supported by coreboot.\n"); + + /* Enable DDR2 */ + regs |= (1 << 7); + pci_write_config8(MEMCTRL, 0x6c, regs); + + /* SPD 5 # of ranks */ + pci_write_config8(MEMCTRL, 0x6d, 0xc0); + + /**********************************************/ + /* Set DRAM Freq (DDR2 533) */ + /**********************************************/ + /* SPD 9 SDRAM Cycle Time */ + GET_SPD(dimm, spds, regs, 9); + + printk_debug("\nDDRII "); + if (spds <= 0x3d) { + printk_debug("533"); + val = DDRII_533; + t = 38; + } else if (spds <= 0x50) { + printk_debug("400"); + val = DDRII_400; + t = 50; + } else if (spds <= 0x60) { + printk_debug("333"); + val = DDRII_333; + t = 60; + } else if (spds <= 0x75) { + printk_debug("266"); + val = DDRII_266; + t = 75; + } else { + printk_debug("200"); + val = DDRII_200; + t = 100; + } + /* To store DDRII frequence */ + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ, val); + + /* Manual reset and adjust DLL when DRAM change frequency + * This is a necessary sequence. + */ + udelay(2000); + regs = pci_read_config8(MEMCTRL, 0x90); + regs |= 0x7; + pci_write_config8(MEMCTRL, 0x90, regs); + udelay(2000); + regs = pci_read_config8(MEMCTRL, 0x90); + regs &= ~0x7; + regs |= val; + pci_write_config8(MEMCTRL, 0x90, regs); + udelay(2000); + regs = pci_read_config8(MEMCTRL, 0x6b); + regs |= 0xc0; + regs &= ~0x10; + pci_write_config8(MEMCTRL, 0x6b, regs); + udelay(1); + regs |= 0x10; + pci_write_config8(MEMCTRL, 0x6b, regs); + udelay(1); + regs &= ~0xc0; + pci_write_config8(MEMCTRL, 0x6b, regs); + regs = pci_read_config8(MEMCTRL, 0x6f); + regs |= 0x1; + pci_write_config8(MEMCTRL, 0x6f, regs); + + /**********************************************/ + /* Set DRAM Timing Setting (DDR2 533) */ + /**********************************************/ + /* SPD 9 18 23 25 CAS Latency NB3DRAM_REG62[2:0] */ + /* Read SPD byte 18 CAS Latency */ + GET_SPD(dimm, spds, regs, SPD_CAS_LAT); + printk_debug("\nCAS Supported "); + if (spds & SPD_CAS_LAT_2) + printk_debug("2 "); + if (spds & SPD_CAS_LAT_3) + printk_debug("3 "); + if (spds & SPD_CAS_LAT_4) + printk_debug("4 "); + if (spds & SPD_CAS_LAT_5) + printk_debug("5 "); + if (spds & SPD_CAS_LAT_6) + printk_debug("6"); + + /* We don't consider CAS = 6, because CX700 doesn't support it */ + printk_debug("\n CAS:"); + if (spds & SPD_CAS_LAT_5) { + printk_debug("Starting at CL5"); + val = 0x3; + /* See whether we can improve it */ + GET_SPD(dimm, tmp, regs, SPD_CAS_LAT_MIN_X_1); + if ((spds & SPD_CAS_LAT_4) && (tmp < 0x50)) { + printk_debug("\n... going to CL4"); + val = 0x2; + } + GET_SPD(dimm, tmp, regs, SPD_CAS_LAT_MIN_X_2); + if ((spds & SPD_CAS_LAT_3) && (tmp < 0x50)) { + printk_debug("\n... going to CL3"); + val = 0x1; + } + } else { + printk_debug("Starting at CL4"); + val = 0x2; + GET_SPD(dimm, tmp, regs, SPD_CAS_LAT_MIN_X_1); + if ((spds & SPD_CAS_LAT_3) && (tmp < 0x50)) { + printk_debug("\n... going to CL3"); + val = 0x1; + } + GET_SPD(dimm, tmp, regs, SPD_CAS_LAT_MIN_X_2); + if ((spds & SPD_CAS_LAT_2) && (tmp < 0x50)) { + printk_debug("\n... going to CL2"); + val = 0x0; + } + } + regs = pci_read_config8(MEMCTRL, 0x62); + regs &= ~0x7; + regs |= val; + pci_write_config8(MEMCTRL, 0x62, regs); + + /* SPD 27 Trp NB3DRAM_REG64[3:2] */ + GET_SPD(dimm, spds, regs, SPD_TRP); + printk_debug("\nTrp %d", spds); + spds >>= 2; + for (val = 2; val <= 5; val++) { + if (spds <= (val * t / 10)) { + val = val - 2; + break; + } + } + val <<= 2; + regs = pci_read_config8(MEMCTRL, 0x64); + regs &= ~0xc; + regs |= val; + pci_write_config8(MEMCTRL, 0x64, regs); + + /* SPD 29 Trcd NB3DRAM_REG64[7:6] */ + GET_SPD(dimm, spds, regs, SPD_TRCD); + printk_debug("\nTrcd %d", spds); + spds >>= 2; + for (val = 2; val <= 5; val++) { + if (spds <= (val * t / 10)) { + val = val - 2; + break; + } + } + val <<= 6; + regs = pci_read_config8(MEMCTRL, 0x64); + regs &= ~0xc0; + regs |= val; + pci_write_config8(MEMCTRL, 0x64, regs); + + /* SPD 30 Tras NB3DRAM_REG62[7:4] */ + GET_SPD(dimm, spds, regs, SPD_TRAS); + printk_debug("\nTras %d", spds); + for (val = 5; val <= 20; val++) { + if (spds <= (val * t / 10)) { + val = val - 5; + break; + } + } + val <<= 4; + regs = pci_read_config8(MEMCTRL, 0x62); + regs &= ~0xf0; + regs |= val; + pci_write_config8(MEMCTRL, 0x62, regs); + + /* SPD 42 SPD 40 Trfc NB3DRAM_REG61[5:0] */ + GET_SPD(dimm, spds, regs, SPD_TRFC); + printk_debug("\nTrfc %d", spds); + tmp = spds; + GET_SPD(dimm, spds, regs, SPD_EX_TRC_TRFC); + if (spds & 0x1) + tmp += 256; + if (spds & 0xe) + tmp++; + for (val = 8; val <= 71; val++) { + if (tmp <= (val * t / 10)) { + val = val - 8; + break; + } + } + regs = pci_read_config8(MEMCTRL, 0x61); + regs &= ~0x3f; + regs |= val; + pci_write_config8(MEMCTRL, 0x61, regs); + + /* SPD 28 Trrd NB3DRAM_REG63[7:6] */ + GET_SPD(dimm, spds, regs, SPD_TRRD); + for (val = 2; val <= 5; val++) { + if (spds <= (val * t / 10)) { + val = val - 2; + break; + } + } + val <<= 6; + printk_debug("\nTrrd val = 0x%x", val); + regs = pci_read_config8(MEMCTRL, 0x63); + regs &= ~0xc0; + regs |= val; + pci_write_config8(MEMCTRL, 0x63, regs); + + /* SPD 36 Twr NB3DRAM_REG61[7:6] */ + GET_SPD(dimm, spds, regs, SPD_TWR); + for (val = 2; val <= 5; val++) { + if (spds <= (val * t / 10)) { + val = val - 2; + break; + } + } + val <<= 6; + printk_debug("\nTwr val = 0x%x", val); + + regs = pci_read_config8(MEMCTRL, 0x61); + regs &= ~0xc0; + regs |= val; + pci_write_config8(MEMCTRL, 0x61, regs); + + /* SPD 37 Twtr NB3DRAM_REG63[1] */ + GET_SPD(dimm, spds, regs, SPD_TWTR); + spds >>= 2; + printk_debug("\nTwtr 0x%x", spds); + if (spds <= (t * 2 / 10)) + val = 0; + else + val = 1; + val <<= 1; + printk_debug("\nTwtr val = 0x%x", val); + + regs = pci_read_config8(MEMCTRL, 0x63); + regs &= ~0x2; + regs |= val; + pci_write_config8(MEMCTRL, 0x63, regs); + + /* SPD 38 Trtp NB3DRAM_REG63[3] */ + GET_SPD(dimm, spds, regs, SPD_TRTP); + spds >>= 2; + printk_debug("\nTrtp 0x%x", spds); + if (spds <= (t * 2 / 10)) + val = 0; + else + val = 1; + val <<= 3; + printk_debug("\nTrtp val = 0x%x", val); + + regs = pci_read_config8(MEMCTRL, 0x63); + regs &= ~0x8; + regs |= val; + pci_write_config8(MEMCTRL, 0x63, regs); + + /**********************************************/ + /* Set DRAM DRDY Setting */ + /**********************************************/ + /* Write slowest value to register */ + tmp = sizeof(Host_Reg_Val) / sizeof(Host_Reg_Val[0]); + for (val = 0; val < tmp; val += 2) + pci_write_config8(HOSTCTRL, Host_Reg_Val[val], Host_Reg_Val[val + 1]); + + /* F2_RX51[7]=0, disable DRDY timing */ + regs = pci_read_config8(HOSTCTRL, 0x51); + regs &= ~0x80; + pci_write_config8(HOSTCTRL, 0x51, regs); + + /**********************************************/ + /* Set DRAM BurstLength */ + /**********************************************/ + regs = pci_read_config8(MEMCTRL, 0x6c); + for (dimm = 0; dimm < DIMM_SOCKETS; dimm++) { + if (pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_REG_BASE + (dimm << 1)))) { + spds = get_spd_data(ctrl, dimm, 16); + if (!(spds & 0x8)) + break; + } + } + if (dimm == 2) + regs |= 0x8; + pci_write_config8(MEMCTRL, 0x6c, regs); + val = pci_read_config8(HOSTCTRL, 0x54); + val &= ~0x10; + if (dimm == 2) + val |= 0x10; + pci_write_config8(HOSTCTRL, 0x54, val); + + /**********************************************/ + /* Set DRAM Driving Setting */ + /**********************************************/ + /* DRAM Timing ODT */ + tmp = sizeof(Dram_Driving_ODT_CTRL) / sizeof(Dram_Driving_ODT_CTRL[0]); + for (val = 0; val < tmp; val += 2) + pci_write_config8(MEMCTRL, Dram_Driving_ODT_CTRL[val], + Dram_Driving_ODT_CTRL[val + 1]); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + val = pci_read_config8(MEMCTRL, 0xd5); + val &= ~0xaa; + switch (regs) { + case 3: + case 2: + val |= 0xa0; + break; + default: + val |= 0x80; + } + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DIMM_NUM); + if (regs == 1) + val |= 0xa; + pci_write_config8(MEMCTRL, 0xd5, val); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DIMM_NUM); + val = pci_read_config8(MEMCTRL, 0xd6); + val &= ~0x2; + if (regs == 1) + val |= 0x2; + pci_write_config8(MEMCTRL, 0xd6, val); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_MAP); + tmp = sizeof(ODT_TBL) / sizeof(ODT_TBL[0]); + for (val = 0; val < tmp; val += 3) { + if (regs == ODT_TBL[val]) { + pci_write_config8(MEMCTRL, 0xd8, ODT_TBL[val + 1]); + /* Store DRAM & NB ODT setting in d0f4_Rxd8 */ + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_NB_ODT, ODT_TBL[val + 2]); + break; + } + } + + pci_write_config8(MEMCTRL, 0xd9, 0x0a); + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + regs--; + regs = regs << 1; + pci_write_config8(MEMCTRL, 0xe0, DQS_DQ_TBL[regs++]); + pci_write_config8(MEMCTRL, 0xe2, DQS_DQ_TBL[regs]); + + /* DRAM Timing CS */ + pci_write_config8(MEMCTRL, 0xe4, 0x66); + + /* DRAM Timing MAA */ + val = 0; + for (dimm = 0; dimm < DIMM_SOCKETS; dimm++) { + if (pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_REG_BASE + (dimm << 1)))) { + spds = get_spd_data(ctrl, dimm, SPD_PRI_WIDTH); + spds = 64 / spds; + if (pci_read_config8 + (PCI_DEV(0, 0, 4), (SCRATCH_REG_BASE + (dimm << 1) + 1))) + spds = spds << 1; + val += spds; + } + } + printk_debug("\nchip #%d", val); + if (val > 18) + regs = 0xdb; + else + regs = 0x86; + pci_write_config8(MEMCTRL, 0xe8, regs); + + /* DRAM Timing MAB */ + pci_write_config8(MEMCTRL, 0xe9, 0x0); + + /* DRAM Timing DCLK VT8454C always 0x66 */ + pci_write_config8(MEMCTRL, 0xe6, 0xaa); + + /**********************************************/ + /* Set DRAM Duty Control */ + /**********************************************/ + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + switch (regs) { + case 1: + case 2: /* 1~2 rank */ + val = 0; + break; + case 3: + case 4: /* 3~4 rank */ + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + if (regs == DDRII_533) + val = 4; + else /* DDRII-400 */ + val = 0; + break; + } + regs = 0xec; + for (t = 0; t < 4; t++) { + pci_write_config8(MEMCTRL, regs, Duty_Control_DDR2[val]); + regs++; + val++; + } + + /**********************************************/ + /* Set DRAM Clock Control */ + /**********************************************/ + /* Write Data Phase */ + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + regs = pci_read_config8(MEMCTRL, 0x75); + regs &= 0xf0; + switch (val) { + case DDRII_533: + pci_write_config8(MEMCTRL, 0x74, 0x07); + regs |= 0x7; + break; + case DDRII_400: + default: + pci_write_config8(MEMCTRL, 0x74, 0x05); + regs |= 0x5; + break; + } + pci_write_config8(MEMCTRL, 0x75, regs); + pci_write_config8(MEMCTRL, 0x76, 0x80); + + /* Clock Phase Control for FeedBack Mode */ + regs = pci_read_config8(MEMCTRL, 0x90); +// regs |= 0x80; + pci_write_config8(MEMCTRL, 0x90, regs); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + switch (regs) { + case DDRII_533: + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + if (regs == 1) + val = 0; + else + val = 3; + break; + case DDRII_400: + default: + val = 6; + break; + } + regs = pci_read_config8(MEMCTRL, 0x91); + regs &= ~0xc0; + regs |= 0x80; + pci_write_config8(MEMCTRL, 0x91, regs); + regs = 0x91; + for (t = 0; t < 3; t++) { + dimm = pci_read_config8(MEMCTRL, regs); + dimm &= ~0x7; + dimm |= ChA_Clk_Phase_DDR2_Table[val]; + pci_write_config8(MEMCTRL, regs, dimm); + regs++; + val++; + } + + pci_write_config8(MEMCTRL, 0x97, 0x12); + pci_write_config8(MEMCTRL, 0x98, 0x33); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_0); + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_2); + if (regs && val) + pci_write_config8(MEMCTRL, 0x9d, 0x00); + else + pci_write_config8(MEMCTRL, 0x9d, 0x0f); + + tmp = sizeof(DQ_DQS_Table) / sizeof(DQ_DQS_Table[0]); + for (val = 0; val < tmp; val += 2) + pci_write_config8(MEMCTRL, DQ_DQS_Table[val], DQ_DQS_Table[val + 1]); + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + if (regs == DDRII_533) + pci_write_config8(MEMCTRL, 0x7b, 0xa0); + else + pci_write_config8(MEMCTRL, 0x7b, 0x10); + + /***************************************************/ + /* Set necessary register before DRAM initialize */ + /***************************************************/ + tmp = sizeof(Mem_Reg_Init) / sizeof(Mem_Reg_Init[0]); + for (val = 0; val < tmp; val += 3) { + regs = pci_read_config8(MEMCTRL, Mem_Reg_Init[val]); + regs &= Mem_Reg_Init[val + 1]; + regs |= Mem_Reg_Init[val + 2]; + pci_write_config8(MEMCTRL, Mem_Reg_Init[val], regs); + } + regs = pci_read_config8(HOSTCTRL, 0x51); + regs &= 0xbf; // Clear bit 6 Disable Read Around Write + pci_write_config8(HOSTCTRL, 0x51, regs); + + regs = pci_read_config8(HOSTCTRL, 0x54); + t = regs >> 5; + val = pci_read_config8(HOSTCTRL, 0x57); + dimm = val >> 5; + if (t == dimm) + t = 0x0; + else + t = 0x1; + regs &= ~0x1; + regs |= t; + val &= ~0x1; + val |= t; + pci_write_config8(HOSTCTRL, 0x57, val); + + regs = pci_read_config8(HOSTCTRL, 0x51); + regs |= t; + pci_write_config8(HOSTCTRL, 0x51, regs); + + regs = pci_read_config8(MEMCTRL, 0x90); + regs &= 0x7; + val = 0; + if (regs < 0x2) + val = 0x80; + regs = pci_read_config8(MEMCTRL, 0x76); + regs &= 0x80; + regs |= val; + pci_write_config8(MEMCTRL, 0x76, regs); + + regs = pci_read_config8(MEMCTRL, 0x6f); + regs |= 0x10; + pci_write_config8(MEMCTRL, 0x6f, regs); + + /***************************************************/ + /* Find suitable DQS value for ChA and ChB */ + /***************************************************/ + // Set DQS output delay for Channel A + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_FREQ); + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_NUM); + switch (regs) { + case DDRII_533: + if (val < 2) + val = 0; + else + val = 2; + break; + case DDRII_400: + default: + if (val < 2) + val = 4; + else + val = 6; + break; + } + for (t = 0; t < 2; t++) + pci_write_config8(MEMCTRL, (0x70 + t), DQSOChA_DDR2_Driving_Table[val + t]); + // Set DQS output delay for Channel B + pci_write_config8(MEMCTRL, 0x72, 0x0); + + regs = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_0); + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_RANK_2); + if (regs && val) + pci_write_config8(MEMCTRL, 0x73, 0xfd); + else + pci_write_config8(MEMCTRL, 0x73, 0x01); +} + +static void sdram_set_registers(const struct mem_controller *ctrl) +{ + c7_cpu_setup(ctrl); + ddr_detect(ctrl); + sdram_set_safe_values(ctrl); +} + +static void step_20_21(const struct mem_controller *ctrl) +{ + u8 val; + + // Step 20 + udelay(200); + + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_NB_ODT); + if (val & DDR2_ODT_150ohm) + read32(0x102200); + else + read32(0x102020); + + /* Step 21. Normal operation */ + print_spew("RAM Enable 5: Normal operation\n"); + do_ram_command(ctrl, RAM_COMMAND_NORMAL); + udelay(3); +} + +static void step_2_19(const struct mem_controller *ctrl) +{ + u32 i; + u8 val; + + // Step 2 + val = pci_read_config8(MEMCTRL, 0x69); + val &= ~0x03; + pci_write_config8(MEMCTRL, 0x69, val); + + /* Step 3 Apply NOP. */ + print_spew("RAM Enable 1: Apply NOP\n"); + do_ram_command(ctrl, RAM_COMMAND_NOP); + + udelay(15); + + // Step 4 + print_spew("SEND: "); + read32(0); + print_spew("OK\n"); + + // Step 5 + udelay(400); + + /* 6. Precharge all. Wait tRP. */ + print_spew("RAM Enable 2: Precharge all\n"); + do_ram_command(ctrl, RAM_COMMAND_PRECHARGE); + + // Step 7 + print_spew("SEND: "); + read32(0); + print_spew("OK\n"); + + /* Step 8. Mode register set. */ + print_spew("RAM Enable 4: Mode register set\n"); + do_ram_command(ctrl, RAM_COMMAND_MRS); //enable dll + + // Step 9 + print_spew("SEND: "); + + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_NB_ODT); + if (val & DDR2_ODT_150ohm) + read32(0x102200); //DDR2_ODT_150ohm + else + read32(0x102020); + print_spew("OK\n"); + + // Step 10 + print_spew("SEND: "); + read32(0x800); + print_spew("OK\n"); + + /* Step 11. Precharge all. Wait tRP. */ + print_spew("RAM Enable 2: Precharge all\n"); + do_ram_command(ctrl, RAM_COMMAND_PRECHARGE); + + // Step 12 + print_spew("SEND: "); + read32(0x0); + print_spew("OK\n"); + + /* Step 13. Perform 8 refresh cycles. Wait tRC each time. */ + print_spew("RAM Enable 3: CBR\n"); + do_ram_command(ctrl, RAM_COMMAND_CBR); + + /* JEDEC says only twice, do 8 times for posterity */ + // Step 16: Repeat Step 14 and 15 another 7 times + for (i = 0; i < 8; i++) { + // Step 14 + read32(0); + print_spew("."); + + // Step 15 + udelay(100); + } + + /* Step 17. Mode register set. Wait 200us. */ + print_spew("\nRAM Enable 4: Mode register set\n"); + + //safe value for now, BL=8, WR=4, CAS=4 + do_ram_command(ctrl, RAM_COMMAND_MRS); + udelay(200); + + /* Use Single Chanel temporarily */ + val = pci_read_config8(MEMCTRL, 0x6c); + if (val & 0x8) { /* Burst Length = 8 */ + val = pci_read_config8(MEMCTRL, 0x62); + val &= 0x7; + i = DDR2_MRS_table[4 + val]; + } else { + val = pci_read_config8(MEMCTRL, 0x62); + val &= 0x7; + i = DDR2_MRS_table[val]; + } + + // Step 18 + val = pci_read_config8(MEMCTRL, 0x61); + val = val >> 6; + i |= DDR2_Twr_table[val]; + read32(i); + + printk_debug("MRS = %08x\n", i); + + udelay(15); + + // Step 19 + val = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_NB_ODT); + if (val & DDR2_ODT_150ohm) + read32(0x103e00); //EMRS OCD Default + else + read32(0x103c20); +} + +static void sdram_set_vr(const struct mem_controller *ctrl, u8 num) +{ + u8 reg, val; + val = 0x54 + (num >> 1); + reg = pci_read_config8(MEMCTRL, val); + reg &= (0xf << (4 * (num & 0x1))); + reg |= (((0x8 | num) << 4) >> (4 * (num & 0x1))); + pci_write_config8(MEMCTRL, val, reg); +} +static void sdram_ending_addr(const struct mem_controller *ctrl, u8 num) +{ + u8 reg, val; + /* Set Ending Address */ + val = 0x40 + num; + reg = pci_read_config8(MEMCTRL, val); + reg += 0x10; + pci_write_config8(MEMCTRL, val, reg); + /* Set Beginning Address */ + val = 0x48 + num; + pci_write_config8(MEMCTRL, val, 0x0); +} + +static void sdram_clear_vr_addr(const struct mem_controller *ctrl, u8 num) +{ + u8 reg, val; + val = 0x54 + (num >> 1); + reg = pci_read_config8(MEMCTRL, val); + reg = ~(0x80 >> (4 * (num & 0x1))); + pci_write_config8(MEMCTRL, val, reg); + val = 0x40 + num; + reg = pci_read_config8(MEMCTRL, val); + reg -= 0x10; + pci_write_config8(MEMCTRL, val, reg); + val = 0x48 + num; + pci_write_config8(MEMCTRL, val, 0x0); +} + +/* Perform sizing DRAM by dynamic method */ +static void sdram_calc_size(const struct mem_controller *ctrl, u8 num) +{ + u8 ca, ra, ba, reg; + ba = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_FLAGS); + if (ba == 8) { + write8(0, 0x0d); + ra = read8(0); + write8((1 << SDRAM1X_RA_12_8bk), 0x0c); + ra = read8(0); + + write8(0, 0x0a); + ca = read8(0); + write8((1 << SDRAM1X_CA_09_8bk), 0x0c); + ca = read8(0); + + write8(0, 0x03); + ba = read8(0); + write8((1 << SDRAM1X_BA2_8bk), 0x02); + ba = read8(0); + write8((1 << SDRAM1X_BA1_8bk), 0x01); + ba = read8(0); + } else { + write8(0, 0x0f); + ra = read8(0); + write8((1 << SDRAM1X_RA_14), 0x0e); + ra = read8(0); + write8((1 << SDRAM1X_RA_13), 0x0d); + ra = read8(0); + write8((1 << SDRAM1X_RA_12), 0x0c); + ra = read8(0); + + write8(0, 0x0c); + ca = read8(0); + write8((1 << SDRAM1X_CA_12), 0x0b); + ca = read8(0); + write8((1 << SDRAM1X_CA_11), 0x0a); + ca = read8(0); + write8((1 << SDRAM1X_CA_09), 0x09); + ca = read8(0); + + write8(0, 0x02); + ba = read8(0); + write8((1 << SDRAM1X_BA1), 0x01); + ba = read8(0); + } + + if (ra < 10 || ra > 15) + die("bad RA"); + if (ca < 8 || ca > 12) + die("bad CA"); + if (ba < 1 || ba > 3) + die("bad BA"); + + /* Calculate MA type save to scratch register */ + reg = 0; + + switch (ra) { + case 12: + reg |= MA_12_Row; + break; + case 13: + reg |= MA_13_Row; + break; + case 14: + reg |= MA_14_Row; + break; + default: + reg |= MA_15_Row; + } + + switch (ca) { + case 9: + reg |= MA_9_Column; + break; + case 10: + reg |= MA_10_Column; + break; + case 11: + reg |= MA_11_Column; + break; + default: + reg |= MA_12_Column; + } + + switch (ba) { + case 3: + reg |= MA_8_Bank; + break; + default: + reg |= MA_4_Bank; + } + + pci_write_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK0_MA_REG + num), reg); + + if (ra >= 13) + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_256M_BIT, 1); + + /* Calculate rank size save to scratch register */ + ra = ra + ca + ba + 3 - 26; /* 1 unit = 64M */ + ra = 1 << ra; + pci_write_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK0_SIZE_REG + num), ra); +} + +static void sdram_enable(const struct mem_controller *ctrl) +{ + u8 reg8; + u8 val, i; + device_t dev; + u8 dl, dh; + u32 quot; + + /* Init Present Bank */ + val = sizeof(Init_Rank_Reg_Table) / sizeof(Init_Rank_Reg_Table[0]); + for (i = 0; i < val; i++) + pci_write_config8(MEMCTRL, Init_Rank_Reg_Table[i], 0x0); + + /* Init other banks */ + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + step_2_19(ctrl); + step_20_21(ctrl); + sdram_clear_vr_addr(ctrl, i); + } + } + +#ifdef MEM_WIDTH_32BIT_MODE + /****************************************************************/ + /* Set Dram 32bit Mode */ + /****************************************************************/ + reg8 = pci_read_config8(MEMCTRL, 0x6c); + reg8 |= 0x20; + pci_write_config(MEMCTRL, 0x6c, reg8); +#endif + + /****************************************************************/ + /* Find the DQSI Low/High bound and save it to Scratch register */ + /****************************************************************/ + for (dl = 0; dl < 0x3f; dl += 2) { + reg8 = dl & 0x3f; + reg8 |= 0x80; /* Set Manual Mode */ + pci_write_config8(MEMCTRL, 0x77, reg8); + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + write32(0, 0x55555555); + write32(4, 0x55555555); + udelay(15); + if (read32(0) != 0x55555555) + break; + if (read32(4) != 0x55555555) + break; + write32(0, 0xaaaaaaaa); + write32(4, 0xaaaaaaaa); + udelay(15); + if (read32(0) != 0xaaaaaaaa) + break; + if (read32(4) != 0xaaaaaaaa) + break; + sdram_clear_vr_addr(ctrl, i); + } + } + if (i == 4) + break; + else + sdram_clear_vr_addr(ctrl, i); + } + printk_debug("\nDQSI Low %08x", dl); + for (dh = dl; dh < 0x3f; dh += 2) { + reg8 = dh & 0x3f; + reg8 |= 0x80; /* Set Manual Mode */ + pci_write_config8(MEMCTRL, 0x77, reg8); + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + + write32(0, 0x55555555); + write32(4, 0x55555555); + udelay(15); + if (read32(0) != 0x55555555) + break; + if (read32(4) != 0x55555555) + break; + write32(0, 0xaaaaaaaa); + write32(4, 0xaaaaaaaa); + udelay(15); + if (read32(0) != 0xaaaaaaaa) + break; + if (read32(4) != 0xaaaaaaaa) + break; + sdram_clear_vr_addr(ctrl, i); + } + } + if (i != 4) { + sdram_clear_vr_addr(ctrl, i); + break; + } + } + printk_debug("\nDQSI High %02x", dh); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_CHA_DQSI_LOW_REG, dl); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_CHA_DQSI_HIGH_REG, dh); + reg8 = pci_read_config8(MEMCTRL, 0X90) & 0X7; + val = DQSI_Rate_Table[reg8]; + quot = dh - dl; + quot = quot * val; + quot >>= 4; + val = quot + dl; + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_ChA_DQSI_REG, val); + reg8 = val & 0x3f; + reg8 |= 0x80; + pci_write_config8(MEMCTRL, 0x77, reg8); + + /****************************************************************/ + /* Find out the lowest Bank Interleave and Set Register */ + /****************************************************************/ +#if 0 + //TODO + reg8 = pci_read_config8(MEMCTRL, 0x69); + reg8 &= ~0xc0; + reg8 |= 0x80; //8 banks + pci_write_config8(MEMCTRL, 0x69, reg8); +#endif + dl = 2; + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + reg8 = get_spd_data(ctrl, (i >> 1), 17); + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + if (reg8 == 4) { + write8(0, 0x02); + val = read8(0); + write8((1 << SDRAM1X_BA1), 0x01); + val = read8(0); + } else { + write8(0, 0x03); + val = read8(0); + write8((1 << SDRAM1X_BA2_8bk), 0x02); + val = read8(0); + write8((1 << SDRAM1X_BA1_8bk), 0x01); + val = read8(0); + } + if (val < dl) + dl = val; + sdram_clear_vr_addr(ctrl, i); + } + } + dl <<= 6; + reg8 = pci_read_config8(MEMCTRL, 0x69); + reg8 &= ~0xc0; + reg8 |= dl; + pci_write_config8(MEMCTRL, 0x69, reg8); + + /****************************************************************/ + /* DRAM Sizing and Fill MA type */ + /****************************************************************/ + for (i = 0; i < 4; i++) { + val = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (val) { + reg8 = get_spd_data(ctrl, (i >> 1), 17); + pci_write_config8(PCI_DEV(0, 0, 4), SCRATCH_FLAGS, reg8); + if (reg8 == 4) { + /* Use MA Type 3 for DRAM sizing */ + reg8 = pci_read_config8(MEMCTRL, 0x50); + reg8 &= 0x11; + reg8 |= 0x66; + pci_write_config8(MEMCTRL, 0x50, reg8); + pci_write_config8(MEMCTRL, 0x51, reg8); + } else { + /* Use MA Type 5 for DRAM sizing */ + reg8 = pci_read_config8(MEMCTRL, 0x50); + reg8 &= 0x11; + reg8 |= 0xaa; + pci_write_config8(MEMCTRL, 0x50, reg8); + pci_write_config8(MEMCTRL, 0x51, reg8); + reg8 = pci_read_config8(MEMCTRL, 0x53); + reg8 &= 0x0f; + reg8 |= 0x90; + pci_write_config8(MEMCTRL, 0x53, reg8); + } + sdram_set_vr(ctrl, i); + val = 0x40 + i; + reg8 = pci_read_config8(MEMCTRL, val); + /* max size 3G for new MA table */ + reg8 += 0x30; + pci_write_config8(MEMCTRL, val, reg8); + /* Set Beginning Address */ + val = 0x48 + i; + pci_write_config8(MEMCTRL, val, 0x0); + + sdram_calc_size(ctrl, i); + + /* Clear */ + val = 0x54 + (i >> 1); + reg8 = pci_read_config8(MEMCTRL, val); + reg8 = ~(0x80 >> (4 * (i & 0x1))); + pci_write_config8(MEMCTRL, val, reg8); + val = 0x40 + i; + reg8 = pci_read_config8(MEMCTRL, val); + reg8 -= 0x30; + pci_write_config8(MEMCTRL, val, reg8); + val = 0x48 + i; + pci_write_config8(MEMCTRL, val, 0x0); + + } + } + /* Clear MA Type */ + reg8 = pci_read_config8(MEMCTRL, 0x50); + reg8 &= 0x11; + pci_write_config8(MEMCTRL, 0x50, reg8); + pci_write_config8(MEMCTRL, 0x51, reg8); + reg8 = pci_read_config8(MEMCTRL, 0x6b); + reg8 &= ~0x08; + pci_write_config8(MEMCTRL, 0x6b, reg8); + + /****************************************************************/ + /* DRAM re-initialize for burst length */ + /****************************************************************/ + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + sdram_set_vr(ctrl, i); + sdram_ending_addr(ctrl, i); + step_2_19(ctrl); + step_20_21(ctrl); + sdram_clear_vr_addr(ctrl, i); + } + } + + /****************************************************************/ + /* Set the MA Type */ + /****************************************************************/ + reg8 = pci_read_config8(MEMCTRL, 0x50); + reg8 &= 0x11; + pci_write_config8(MEMCTRL, 0x50, reg8); + + reg8 = pci_read_config8(MEMCTRL, 0x51); + reg8 &= 0x11; + pci_write_config8(MEMCTRL, 0x51, reg8); + + reg8 = pci_read_config8(MEMCTRL, 0x6b); + reg8 &= ~0x08; + pci_write_config8(MEMCTRL, 0x6b, reg8); + + for (i = 0; i < 4; i += 2) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK0_MA_REG + i)); + reg8 &= (MA_Bank + MA_Column); + val = pci_read_config8(MEMCTRL, 0x50); + if (i == 0) { + reg8 <<= 4; + val &= 0x1f; + } else + val &= 0xf1; + val |= reg8; + pci_write_config8(MEMCTRL, 0x50, val); + } + } + + /****************************************************************/ + /* Set Start and Ending Address */ + /****************************************************************/ + dl = 0; /* Begin Address */ + dh = 0; /* Ending Address */ + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK0_SIZE_REG + i)); + if (reg8 == 0) + continue; + dh += reg8; + pci_write_config8(MEMCTRL, (0x40 + i), dh); + pci_write_config8(MEMCTRL, (0x48 + i), dl); + dl = dh; + } + } + dh <<= 2; + // F7_Rx57 Ending address mirror register + pci_write_config8(PCI_DEV(0, 0, 7), 0x57, dh); + dev = pci_locate_device(PCI_ID(0x1106, 0x324e), 0); + pci_write_config8(dev, 0x57, dh); + // LOW TOP Address + pci_write_config8(MEMCTRL, 0x88, dh); + pci_write_config8(MEMCTRL, 0x85, dh); + // also program vlink mirror + pci_write_config8(PCI_DEV(0, 0, 7), 0xe5, dh); + + /****************************************************************/ + /* Set Physical to Virtual Rank mapping */ + /****************************************************************/ + pci_write_config32(MEMCTRL, 0x54, 0x0); + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) { + reg8 = pci_read_config8(MEMCTRL, (0x54 + (i >> 1))); + if (i & 0x1) { /* Odd Rank */ + reg8 &= 0xf0; + reg8 |= (0x8 | i); + } else { /* Even Rank */ + + reg8 &= 0x0f; + reg8 |= ((0x8 | i) << 4); + } + pci_write_config8(MEMCTRL, (0x54 + (i >> 1)), reg8); + } + } + + /****************************************************************/ + /* Set DRAM Refresh Counter */ + /****************************************************************/ + val = pci_read_config8(MEMCTRL, 0X90) & 0X7; + val <<= 1; + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), SCRATCH_DRAM_256M_BIT); + if (reg8) + val++; + pci_write_config8(MEMCTRL, 0x6a, REFC_Table[val]); + + /****************************************************************/ + /* Chipset Performance UP and other setting after DRAM Sizing */ + /****************************************************************/ + /* Dram Registers */ + val = sizeof(Dram_Table) / sizeof(Dram_Table[0]); + for (i = 0; i < val; i += 3) { + reg8 = pci_read_config8(MEMCTRL, Dram_Table[i]); + reg8 &= Dram_Table[i + 1]; + reg8 |= Dram_Table[i + 2]; + pci_write_config8(MEMCTRL, Dram_Table[i], reg8); + } + + /* Host Registers */ + val = sizeof(Host_Table) / sizeof(Host_Table[0]); + for (i = 0; i < val; i += 3) { + reg8 = pci_read_config8(HOSTCTRL, Host_Table[i]); + reg8 &= Host_Table[i + 1]; + reg8 |= Host_Table[i + 2]; + pci_write_config8(HOSTCTRL, Host_Table[i], reg8); + } + + /* PM Registers */ +#ifdef SETUP_PM_REGISTERS + val = sizeof(PM_Table) / sizeof(PM_Table[0]); + for (i = 0; i < val; i += 3) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), PM_Table[i]); + reg8 &= PM_Table[i + 1]; + reg8 |= PM_Table[i + 2]; + pci_write_config8(PCI_DEV(0, 0, 4), PM_Table[i], reg8); + } +#endif + pci_write_config8(HOSTCTRL, 0x5d, 0xb2); + + /****************************************************************/ + /* UMA registers for N-series projects */ + /****************************************************************/ + + /* Manual setting frame buffer bank */ + for (i = 0; i < 4; i++) { + reg8 = pci_read_config8(PCI_DEV(0, 0, 4), (SCRATCH_RANK_0 + i)); + if (reg8) + val = i; + } + pci_write_config8(MEMCTRL, 0xb0, val); + reg8 = 0x40; // Frame buffer size 64M + reg8 |= 0x80; // VGA Enable + reg8 |= 0x0a; // A[31:28] = 1010b + pci_write_config8(MEMCTRL, 0xa1, reg8); + +#ifdef ECC + // Clear Ecc + outl(0x80000180, 0xcf8); + outb(0xff, 0xcfc); + // Enable Ecc + outl(0x80000188, 0xcf8); + outb(0xcf, 0xcfc); + + reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0xa5); + reg8 |= 0x10; + pci_write_config8(PCI_DEV(0, 0, 0), 0xa5, reg8); + + reg8 = pci_read_config8(PCI_DEV(0, 0, 0), 0x91); + reg8 |= 0x20; + pci_write_config8(PCI_DEV(0, 0, 0), 0x91, reg8); +#endif + + static const struct regmask { + u8 reg; + u8 mask; + u8 val; + } b0d1f0[] = { + { 0x40, 0x00, 0x8b}, + { 0x41, 0x80, 0x43}, + { 0x42, 0x00, 0x62}, + { 0x43, 0x00, 0x44}, + { 0x44, 0x00, 0x34}, + { 0x45, 0x00, 0x72} + }, b0d0f3[] = { + { 0x53, 0xf0, 0x0f}, + { 0x60, 0x00, 0x03}, + { 0x65, 0x00, 0xd9}, + { 0x66, 0x00, 0x80}, + { 0x67, 0x00, 0x00}, + { 0x68, 0x00, 0x01}, + { 0x69, 0xe0, 0x03}, + { 0x6b, 0x00, 0x10}, + { 0x6c, 0xc1, 0x08}, + { 0x6e, 0x00, 0x89}, + { 0x6f, 0x00, 0x51}, + { 0x75, ~0x40, 0x40}, + { 0x76, 0x8f, 0x00}, + { 0x7b, 0x00, 0xa0}, + { 0x86, 0x01, 0x24}, + { 0x86, 0x04, 0x29}, + { 0x8c, 0x00, 0x00}, + { 0x8d, 0x00, 0x00}, + { 0x95, ~0x40, 0x00}, + { 0xa2, 0x00, 0x44}, + { 0xb1, 0x00, 0xaa} + }, b0d0f0[] = { + { 0x4d, 0x00, 0x24}, + { 0x4f, 0x00, 0x01}, + { 0xbc, 0x00, 0x21}, + { 0xbe, 0x00, 0x00}, + { 0xbf, 0x7f, 0x80} + }, b0d17f0[] = { + { 0x40, ~0x01, 0x01}, // enable timer/counter shadow registers + { 0x67, ~0x03, 0x01}, + { 0x5b, ~0x01, 0x00}, + { 0x8d, ~0x02, 0x02}, + { 0x97, ~0x80, 0x00}, + { 0xd2, ~0x18, 0x00}, + { 0xe2, ~0x36, 0x06}, + { 0xe4, ~0x80, 0x00}, + { 0xe5, 0x00, 0x40}, + { 0xe6, 0x00, 0x20}, + { 0xe7, ~0xd0, 0xc0}, + { 0xec, ~0x08, 0x00} + }, b0d17f7[] = { + { 0x4e, ~0x80, 0x80}, + { 0x4f, ~(1 << 6), 1 << 6 }, /* PG_CX700: 14.1.1 enable P2P Bridge Header for External PCI Bus */ + { 0x74, ~0x00, 0x04}, /* PG_CX700: 14.1.2 APIC FSB directly up to snmic, not on pci */ + { 0x7c, ~0x00, 0x02}, /* PG_CX700: 14.1.1 APIC FSB directly up to snmic, not on pci */ + { 0xe6, 0x0, 0x04} // MSI post + }, b0d19f0[] = { /* P2PE */ + { 0x42, ~0x08, 0x08}, // Disable HD Audio, + { 0x40, ~0xc0, 0x80} // 14.1.3.1.1 of the PG: extended cfg mode for pcie. enable capability, but don't activate + }, b0d0f2[] = { + { 0x50, ~0x40, 0x88}, + { 0x51, 0x80, 0x7b}, + { 0x52, 0x90, 0x6f}, + { 0x53, 0x00, 0x88}, + { 0x54, 0xe4, 0x16}, + { 0x55, 0xf2, 0x04}, + { 0x56, 0x0f, 0x00}, + { 0x57, ~0x04, 0x00}, + { 0x5d, 0x00, 0xb2}, + { 0x5e, 0x00, 0x88}, + { 0x5f, 0x00, 0xc7}, + { 0x5c, 0x00, 0x01} + }; + + REGISTERPRESET(0, 0, 0, b0d0f0); + REGISTERPRESET(0, 0, 2, b0d0f2); + REGISTERPRESET(0, 0, 3, b0d0f3); + REGISTERPRESET(0, 1, 0, b0d1f0); + REGISTERPRESET(0, 17, 0, b0d17f0); + REGISTERPRESET(0, 17, 7, b0d17f7); + REGISTERPRESET(0, 19, 0, b0d19f0); +} |