From 8e0586200b61cd5bf4a3f59bf7ac68efc6f9ac17 Mon Sep 17 00:00:00 2001 From: Greg Watson Date: Sat, 17 Apr 2004 02:36:47 +0000 Subject: start of epia-m port git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1512 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- src/northbridge/via/vt8623/Config.lb | 2 + src/northbridge/via/vt8623/chip.h | 5 + src/northbridge/via/vt8623/northbridge.c | 122 ++++++++++ src/northbridge/via/vt8623/northbridge.h | 6 + src/northbridge/via/vt8623/raminit.c | 394 +++++++++++++++++++++++++++++++ src/northbridge/via/vt8623/raminit.h | 8 + 6 files changed, 537 insertions(+) create mode 100644 src/northbridge/via/vt8623/Config.lb create mode 100644 src/northbridge/via/vt8623/chip.h create mode 100644 src/northbridge/via/vt8623/northbridge.c create mode 100644 src/northbridge/via/vt8623/northbridge.h create mode 100644 src/northbridge/via/vt8623/raminit.c create mode 100644 src/northbridge/via/vt8623/raminit.h (limited to 'src/northbridge/via') diff --git a/src/northbridge/via/vt8623/Config.lb b/src/northbridge/via/vt8623/Config.lb new file mode 100644 index 0000000000..4a0c2c8658 --- /dev/null +++ b/src/northbridge/via/vt8623/Config.lb @@ -0,0 +1,2 @@ +config chip.h +object northbridge.o diff --git a/src/northbridge/via/vt8623/chip.h b/src/northbridge/via/vt8623/chip.h new file mode 100644 index 0000000000..b689f0dedd --- /dev/null +++ b/src/northbridge/via/vt8623/chip.h @@ -0,0 +1,5 @@ +struct northbridge_via_vt8601_config +{ +}; + +extern struct chip_control northbridge_via_vt8601_control; diff --git a/src/northbridge/via/vt8623/northbridge.c b/src/northbridge/via/vt8623/northbridge.c new file mode 100644 index 0000000000..5f5e5d9dd8 --- /dev/null +++ b/src/northbridge/via/vt8623/northbridge.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "chip.h" +#include "northbridge.h" + +static const uint8_t ramregs[] = {0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x56, 0x57}; + +struct mem_range *sizeram(void) +{ + unsigned long mmio_basek; + static struct mem_range mem[10]; + device_t dev; + int i, idx; + unsigned char rambits; + + dev = dev_find_slot(0, 0); + if (!dev) { + printk_err("Cannot find PCI: 0:0\n"); + return 0; + } + mem[0].basek = 0; + mem[0].sizek = 65536; + idx = 1; + while(idx < sizeof(mem)/sizeof(mem[0])) { + mem[idx].basek = 0; + mem[idx].sizek = 0; + idx++; + } + for(rambits = 0, i = 0; i < sizeof(ramregs)/sizeof(ramregs[0]); i++) { + unsigned char reg; + reg = pci_read_config8(dev, ramregs[i]); + /* these are ENDING addresses, not sizes. + * if there is memory in this slot, then reg will be > rambits. + * So we just take the max, that gives us total. + * We take the highest one to cover for once and future linuxbios + * bugs. We warn about bugs. + */ + if (reg > rambits) + rambits = reg; + if (reg < rambits) + printk_err("ERROR! register 0x%x is not set!\n", + ramregs[i]); + } + + printk_debug("I would set ram size to 0x%x Kbytes\n", (rambits)*8*1024); + mem[0].sizek = rambits*8*1024; +#if 1 + for(i = 0; i < idx; i++) { + printk_debug("mem[%d].basek = %08x mem[%d].sizek = %08x\n", + i, mem[i].basek, i, mem[i].sizek); + } +#endif + + return mem; +} +static void enumerate(struct chip *chip) +{ + extern struct device_operations default_pci_ops_bus; + chip_enumerate(chip); + chip->dev->ops = &default_pci_ops_bus; +} + +/* + * This fixup is based on capturing values from an Award bios. Without + * this fixup the DMA write performance is awful (i.e. hdparm -t /dev/hda is 20x + * slower than normal, ethernet drops packets). + * Apparently these registers govern some sort of bus master behavior. + */ +static void random_fixup() { + device_t pcidev = dev_find_slot(0, 0); + + printk_spew("VT8601 random fixup ...\n"); + if (pcidev) { + pci_write_config8(pcidev, 0x70, 0xc0); + pci_write_config8(pcidev, 0x71, 0x88); + pci_write_config8(pcidev, 0x72, 0xec); + pci_write_config8(pcidev, 0x73, 0x0c); + pci_write_config8(pcidev, 0x74, 0x0e); + pci_write_config8(pcidev, 0x75, 0x81); + pci_write_config8(pcidev, 0x76, 0x52); + } +} + +static void northbridge_init(struct chip *chip, enum chip_pass pass) +{ + + struct northbridge_via_vt8601_config *conf = + (struct northbridge_via_vt8601_config *)chip->chip_info; + + switch (pass) { + case CONF_PASS_PRE_PCI: + break; + + case CONF_PASS_POST_PCI: + break; + + case CONF_PASS_PRE_BOOT: + random_fixup(); + break; + + default: + /* nothing yet */ + break; + } +} + +struct chip_control northbridge_via_vt8601_control = { + .enumerate = enumerate, + .enable = northbridge_init, + .name = "VIA vt8601 Northbridge", +}; diff --git a/src/northbridge/via/vt8623/northbridge.h b/src/northbridge/via/vt8623/northbridge.h new file mode 100644 index 0000000000..d7f8e605b8 --- /dev/null +++ b/src/northbridge/via/vt8623/northbridge.h @@ -0,0 +1,6 @@ +#ifndef NORTHBRIDGE_VIA_VT8601_H +#define NORTHBRIDGE_VIA_VT8601_H + +extern unsigned int vt8601_scan_root_bus(device_t root, unsigned int max); + +#endif /* NORTHBRIDGE_VIA_VT8601_H */ diff --git a/src/northbridge/via/vt8623/raminit.c b/src/northbridge/via/vt8623/raminit.c new file mode 100644 index 0000000000..f295c9c737 --- /dev/null +++ b/src/northbridge/via/vt8623/raminit.c @@ -0,0 +1,394 @@ +#include +#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. + */ + +/* 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 + */ +/* converted to C 9/2003 Ron Minnich */ + +/* 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 +#endif + +// Set to 1 if your DIMMs are CL=2 +#ifndef DIMM_CL2 +#define DIMM_CL2 0 +#endif + +void dimms_read(unsigned long x) +{ + 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; + } +} + +void dimms_write(int x) +{ + uint8_t c; + unsigned long eax = x; + for(c = 0; c < 6; c++) { + *(volatile unsigned long *) eax = 0; + eax += 0x10000000; + } +} + + + +#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); +} +#else +#define setnorthb pci_write_config8 +#endif + +void +dumpnorth(device_t north) +{ + uint8_t r, c; + for(r = 0; r < 256; 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"); + } +} + +static void sdram_set_registers(const struct mem_controller *ctrl) +{ + 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 + + // 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 + + /* 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); +} + +/* 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. + */ + /* we may run out of registers ... */ + unsigned int banks, rows, cols, reg; + unsigned int value = 0; + unsigned int module = ((0x50 + slot) << 1) + 1; + /* is the module there? if byte 2 is not 4, then we'll assume it + * is useless. + */ + 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; + } + print_info("\r\n"); + return value; + +} + +static int +spd_num_chips(unsigned char slot) +{ + unsigned int module = ((0x50 + slot) << 1) + 1; + unsigned int width; + + width = smbus_read_byte(module, 13); + if (width == 0) + width = 8; + return 64 / width; +} + +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(0xa0, 27); + if (val < 2*T133) + Trp = 1; + val = smbus_read_byte(0xa0, 30); + if (val < 5*T133) + Tras = 0; + val = smbus_read_byte(0xa0, 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); + */ +} + +static void set_ma_mapping(device_t north, int slot, int type) +{ + 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); +} + + +static void sdram_enable(int controllers, const struct mem_controller *ctrl) +{ + 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 + udelay(200); + print_debug("NORMAL\r\n"); + /* set to normal mode */ + pci_write_config8(north,0x6C, 0x08); + + dimms_write(0x55aa55aa); + dimms_read(0); + 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); + } + print_err("vt8601 done\r\n"); + dumpnorth(north); +} diff --git a/src/northbridge/via/vt8623/raminit.h b/src/northbridge/via/vt8623/raminit.h new file mode 100644 index 0000000000..b6d2339df3 --- /dev/null +++ b/src/northbridge/via/vt8623/raminit.h @@ -0,0 +1,8 @@ +#ifndef RAMINIT_H +#define RAMINIT_H + +struct mem_controller { + int empty; +}; + +#endif /* RAMINIT_H */ -- cgit v1.2.3