Idwer Vollering (vidwer@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/411
-gerrit
commit 53223286a4d9d9c0a87aec1d29645d8121d7b502 Author: Idwer idwer@localhost.localdomain Date: Sat Nov 5 15:31:55 2011 +0100
Add code to set the clock speed for Winbond W83627THF/THG.
Change-Id: If92d96d117683cc59081061d5ac93aa23cb87327 Signed-off-by: Idwer Vollering vidwer@gmail.com --- src/cpu/intel/model_f2x/Kconfig | 3 + src/cpu/intel/model_f2x/Makefile.inc | 1 + src/cpu/intel/model_f2x/cache_as_ram.inc | 376 ++++++++++ src/cpu/intel/socket_mPGA478/Kconfig | 1 + src/cpu/intel/socket_mPGA478/Makefile.inc | 2 +- src/include/device/pci_ids.h | 6 +- src/mainboard/asrock/Kconfig | 5 +- src/mainboard/asrock/p4i65gv/Kconfig | 53 ++ src/mainboard/asrock/p4i65gv/Makefile.inc | 1 + src/mainboard/asrock/p4i65gv/chip.h | 22 + src/mainboard/asrock/p4i65gv/devicetree.cb | 49 ++ src/mainboard/asrock/p4i65gv/irq_tables.c | 63 ++ src/mainboard/asrock/p4i65gv/mainboard.c | 26 + src/mainboard/asrock/p4i65gv/romstage.c | 84 +++ src/mainboard/asrock/p4i65gv/rtl8139.c | 46 ++ src/mainboard/asrock/p4i65gv/watchdog.c | 36 + src/mainboard/asus/Kconfig | 4 +- src/mainboard/asus/p4p800-vm/Kconfig | 53 ++ src/mainboard/asus/p4p800-vm/Makefile.inc | 1 + src/mainboard/asus/p4p800-vm/chip.h | 22 + src/mainboard/asus/p4p800-vm/devicetree.cb | 49 ++ src/mainboard/asus/p4p800-vm/e100.c | 46 ++ src/mainboard/asus/p4p800-vm/irq_tables.c | 63 ++ src/mainboard/asus/p4p800-vm/mainboard.c | 26 + src/mainboard/asus/p4p800-vm/romstage.c | 84 +++ src/mainboard/asus/p4p800-vm/watchdog.c | 36 + src/northbridge/intel/Kconfig | 1 + src/northbridge/intel/Makefile.inc | 1 + src/northbridge/intel/i865/Kconfig | 25 + src/northbridge/intel/i865/Makefile.inc | 2 + src/northbridge/intel/i865/TODO | 16 + src/northbridge/intel/i865/chip.h | 25 + src/northbridge/intel/i865/debug.c | 139 ++++ src/northbridge/intel/i865/i865.h | 89 +++ src/northbridge/intel/i865/northbridge.c | 171 +++++ src/northbridge/intel/i865/raminit.c | 1031 ++++++++++++++++++++++++++ src/northbridge/intel/i865/raminit.h | 181 +++++ src/northbridge/intel/i865/reset_test.c | 38 + src/southbridge/intel/i82801ex/early_smbus.c | 4 +- src/southbridge/intel/i82801ex/smbus.h | 3 + src/superio/winbond/w83627thg/early_serial.c | 11 + 41 files changed, 2888 insertions(+), 7 deletions(-)
diff --git a/src/cpu/intel/model_f2x/Kconfig b/src/cpu/intel/model_f2x/Kconfig index 50cac79..ca57343 100644 --- a/src/cpu/intel/model_f2x/Kconfig +++ b/src/cpu/intel/model_f2x/Kconfig @@ -1,3 +1,6 @@ config CPU_INTEL_MODEL_F2X bool select SMP + select MMX + select SSE + select CACHE_AS_RAM diff --git a/src/cpu/intel/model_f2x/Makefile.inc b/src/cpu/intel/model_f2x/Makefile.inc index c393343..d4ddb7b 100644 --- a/src/cpu/intel/model_f2x/Makefile.inc +++ b/src/cpu/intel/model_f2x/Makefile.inc @@ -1 +1,2 @@ +cpu_incs += $(src)/cpu/intel/model_f2x/cache_as_ram.inc driver-y += model_f2x_init.c diff --git a/src/cpu/intel/model_f2x/cache_as_ram.inc b/src/cpu/intel/model_f2x/cache_as_ram.inc new file mode 100644 index 0000000..7742a68 --- /dev/null +++ b/src/cpu/intel/model_f2x/cache_as_ram.inc @@ -0,0 +1,376 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2000, 2007 Ronald G. Minnich rminnich@gmail.com + * Copyright (C) 2005 Eswar Nallusamy, LANL + * Copyright (C) 2005 Tyan (written by Yinghai Lu for Tyan) + * Copyright (C) 2007-2010 coresystems GmbH + * Copyright (C) 2007 Carl-Daniel Hailfinger + * + * 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 <cpu/x86/stack.h> +#include <cpu/x86/mtrr.h> +#include <cpu/x86/lapic_def.h> +#include <cpu/x86/post_code.h> + +#define CacheSize CONFIG_DCACHE_RAM_SIZE +#define CacheBase (0xd0000 - CacheSize) + + /* Save the BIST result. */ + movl %eax, %ebp + +CacheAsRam: + /* Check whether the processor has HT capability. */ + movl $01, %eax + cpuid + btl $28, %edx + jnc NotHtProcessor + bswapl %ebx + cmpb $01, %bh + jbe NotHtProcessor + + /* + * It is a HT processor. Send SIPI to the other logical processor + * within this processor so that the CAR related common system + * registers are programmed accordingly. + */ + + /* + * Use some register that is common to both logical processors + * as semaphore. Refer Appendix B, Vol.3. + */ + xorl %eax, %eax + xorl %edx, %edx + movl $MTRRfix64K_00000_MSR, %ecx + wrmsr + + /* + * Figure out the logical AP's APIC ID; the following logic will + * work only for processors with 2 threads. + * Refer to Vol 3. Table 7-1 for details about this logic. + */ + movl $0xFEE00020, %esi + movl (%esi), %ebx + andl $0xFF000000, %ebx + bswapl %ebx + btl $0, %ebx + jnc LogicalAP0 + andb $0xFE, %bl + jmp Send_SIPI +LogicalAP0: + orb $0x01, %bl +Send_SIPI: + bswapl %ebx /* EBX - logical AP's APIC ID. */ + + /* + * Fill up the IPI command registers in the Local APIC mapped to + * default address and issue SIPI to the other logical processor + * within this processor die. + */ +Retry_SIPI: + movl %ebx, %eax + movl $0xFEE00310, %esi + movl %eax, (%esi) + + /* SIPI vector - F900:0000 */ + movl $0x000006F9, %eax + movl $0xFEE00300, %esi + movl %eax, (%esi) + + movl $0x30, %ecx +SIPI_Delay: + pause + decl %ecx + jnz SIPI_Delay + + movl (%esi), %eax + andl $0x00001000, %eax + jnz Retry_SIPI + + /* Wait for the Logical AP to complete initialization. */ +LogicalAP_SIPINotdone: + movl $MTRRfix64K_00000_MSR, %ecx + rdmsr + orl %eax, %eax + jz LogicalAP_SIPINotdone + +NotHtProcessor: + /* Set the default memory type and enable fixed and variable MTRRs. */ + movl $MTRRdefType_MSR, %ecx + xorl %edx, %edx + movl $(MTRRdefTypeEn | MTRRdefTypeFixEn), %eax + wrmsr + + /* Clear all MTRRs. */ + xorl %edx, %edx + movl $all_mtrr_msrs, %esi + +clear_fixed_var_mtrr: + lodsl (%esi), %eax + testl %eax, %eax + jz clear_fixed_var_mtrr_out + + movl %eax, %ecx + xorl %eax, %eax + wrmsr + + jmp clear_fixed_var_mtrr + +all_mtrr_msrs: + /* fixed MTRR MSRs */ + .long MTRRfix64K_00000_MSR + .long MTRRfix16K_80000_MSR + .long MTRRfix16K_A0000_MSR + .long MTRRfix4K_C0000_MSR + .long MTRRfix4K_C8000_MSR + .long MTRRfix4K_D0000_MSR + .long MTRRfix4K_D8000_MSR + .long MTRRfix4K_E0000_MSR + .long MTRRfix4K_E8000_MSR + .long MTRRfix4K_F0000_MSR + .long MTRRfix4K_F8000_MSR + + /* var MTRR MSRs */ + .long MTRRphysBase_MSR(0) + .long MTRRphysMask_MSR(0) + .long MTRRphysBase_MSR(1) + .long MTRRphysMask_MSR(1) + .long MTRRphysBase_MSR(2) + .long MTRRphysMask_MSR(2) + .long MTRRphysBase_MSR(3) + .long MTRRphysMask_MSR(3) + .long MTRRphysBase_MSR(4) + .long MTRRphysMask_MSR(4) + .long MTRRphysBase_MSR(5) + .long MTRRphysMask_MSR(5) + .long MTRRphysBase_MSR(6) + .long MTRRphysMask_MSR(6) + .long MTRRphysBase_MSR(7) + .long MTRRphysMask_MSR(7) + + .long 0x000 /* NULL, end of table */ + +clear_fixed_var_mtrr_out: + +/* + * 0x06 is the WB IO type for a given 4k segment. + * segs is the number of 4k segments in the area of the particular + * register we want to use for CAR. + * reg is the register where the IO type should be stored. + */ +.macro extractmask segs, reg +.if \segs <= 0 + /* + * The xorl here is superfluous because at the point of first execution + * of this macro, %eax and %edx are cleared. Later invocations of this + * macro will have a monotonically increasing segs parameter. + */ + xorl \reg, \reg +.elseif \segs == 1 + movl $0x06000000, \reg /* WB IO type */ +.elseif \segs == 2 + movl $0x06060000, \reg /* WB IO type */ +.elseif \segs == 3 + movl $0x06060600, \reg /* WB IO type */ +.elseif \segs >= 4 + movl $0x06060606, \reg /* WB IO type */ +.endif +.endm + +/* + * carsize is the cache size in bytes we want to use for CAR. + * windowoffset is the 32k-aligned window into CAR size. + */ +.macro simplemask carsize, windowoffset + .set gas_bug_workaround,(((\carsize - \windowoffset) / 0x1000) - 4) + extractmask gas_bug_workaround, %eax + .set gas_bug_workaround,(((\carsize - \windowoffset) / 0x1000)) + extractmask gas_bug_workaround, %edx + /* + * Without the gas bug workaround, the entire macro would consist + * only of the two lines below: + * extractmask (((\carsize - \windowoffset) / 0x1000) - 4), %eax + * extractmask (((\carsize - \windowoffset) / 0x1000)), %edx + */ +.endm + +#if CacheSize > 0x10000 +#error Invalid CAR size, must be at most 64k. +#endif +#if CacheSize < 0x1000 +#error Invalid CAR size, must be at least 4k. This is a processor limitation. +#endif +#if (CacheSize & (0x1000 - 1)) +#error Invalid CAR size, is not a multiple of 4k. This is a processor limitation. +#endif + +#if CacheSize > 0x8000 + /* Enable caching for 32K-64K using fixed MTRR. */ + movl $MTRRfix4K_C0000_MSR, %ecx + simplemask CacheSize, 0x8000 + wrmsr +#endif + + /* Enable caching for 0-32K using fixed MTRR. */ + movl $MTRRfix4K_C8000_MSR, %ecx + simplemask CacheSize, 0 + wrmsr + +#if CONFIG_XIP_ROM_SIZE + + /* + * Enable write base caching so we can do execute in place (XIP) + * on the flash ROM. + */ + movl $MTRRphysBase_MSR(1), %ecx + xorl %edx, %edx + /* + * IMPORTANT: The following calculation _must_ be done at runtime. See + * http://www.coreboot.org/pipermail/coreboot/2010-October/060855.html + */ + movl $copy_and_run, %eax + andl $(~(CONFIG_XIP_ROM_SIZE - 1)), %eax + orl $MTRR_TYPE_WRBACK, %eax + wrmsr + + movl $MTRRphysMask_MSR(1), %ecx + movl $0x0000000f, %edx + movl $(~(CONFIG_XIP_ROM_SIZE - 1) | MTRRphysMaskValid), %eax + wrmsr +#endif /* CONFIG_XIP_ROM_SIZE */ + + /* Enable cache. */ + movl %cr0, %eax + andl $(~((1 << 30) | (1 << 29))), %eax + movl %eax, %cr0 + + /* Read the range with lodsl. */ + movl $CacheBase, %esi + cld + movl $(CacheSize >> 2), %ecx + rep lodsl + + /* Clear the range. */ + movl $CacheBase, %edi + movl $(CacheSize >> 2), %ecx + xorl %eax, %eax + rep stosl + +#if 0 + /* Check the cache as ram. */ + movl $CacheBase, %esi + movl $(CacheSize >> 2), %ecx +.xin1: + movl %esi, %eax + movl %eax, (%esi) + decl %ecx + je .xout1 + add $4, %esi + jmp .xin1 +.xout1: + + movl $CacheBase, %esi + // movl $(CacheSize >> 2), %ecx + movl $4, %ecx +.xin1x: + movl %esi, %eax + + movl $0x4000, %edx + movb %ah, %al +.testx1: + outb %al, $0x80 + decl %edx + jnz .testx1 + + movl (%esi), %eax + cmpb 0xff, %al + je .xin2 /* Don't show. */ + + movl $0x4000, %edx +.testx2: + outb %al, $0x80 + decl %edx + jnz .testx2 + +.xin2: + decl %ecx + je .xout1x + add $4, %esi + jmp .xin1x +.xout1x: +#endif + + movl $(CacheBase + CacheSize - 4), %eax + movl %eax, %esp +lout: + /* Restore the BIST result. */ + movl %ebp, %eax + + /* We need to set EBP? No need. */ + movl %esp, %ebp + pushl %eax /* BIST */ + call main + + /* We don't need CAR from now on. */ + + /* Disable cache. */ + movl %cr0, %eax + orl $(1 << 30), %eax + movl %eax, %cr0 + + /* Clear sth. */ + movl $MTRRfix4K_C8000_MSR, %ecx + xorl %edx, %edx + xorl %eax, %eax + wrmsr + +#if CONFIG_DCACHE_RAM_SIZE > 0x8000 + movl $MTRRfix4K_C0000_MSR, %ecx + wrmsr +#endif + + /* + * Set the default memory type and disable fixed + * and enable variable MTRRs. + */ + movl $MTRRdefType_MSR, %ecx + xorl %edx, %edx + movl $MTRRdefTypeEn, %eax /* Enable variable and disable fixed MTRRs. */ + wrmsr + + /* Enable cache. */ + movl %cr0, %eax + andl $(~((1 << 30) | (1 << 29))), %eax + movl %eax, %cr0 + + /* Clear boot_complete flag. */ + xorl %ebp, %ebp +__main: + post_code(POST_PREPARE_RAMSTAGE) + cld /* Clear direction flag. */ + + movl %ebp, %esi + + movl $ROMSTAGE_STACK, %esp + movl %esp, %ebp + pushl %esi + call copy_and_run + +.Lhlt: + post_code(POST_DEAD_CODE) + hlt + jmp .Lhlt + diff --git a/src/cpu/intel/socket_mPGA478/Kconfig b/src/cpu/intel/socket_mPGA478/Kconfig index 8c447c9..c17780f 100644 --- a/src/cpu/intel/socket_mPGA478/Kconfig +++ b/src/cpu/intel/socket_mPGA478/Kconfig @@ -2,3 +2,4 @@ config CPU_INTEL_SOCKET_MPGA478 bool select CPU_INTEL_MODEL_69X select CPU_INTEL_MODEL_6DX + select CPU_INTEL_MODEL_F2X diff --git a/src/cpu/intel/socket_mPGA478/Makefile.inc b/src/cpu/intel/socket_mPGA478/Makefile.inc index ba2f13c..c3742f3 100644 --- a/src/cpu/intel/socket_mPGA478/Makefile.inc +++ b/src/cpu/intel/socket_mPGA478/Makefile.inc @@ -1,6 +1,7 @@ ramstage-y += socket_mPGA478.c subdirs-y += ../model_69x subdirs-y += ../model_6dx +subdirs-y += ../model_f2x subdirs-y += ../../x86/tsc subdirs-y += ../../x86/mtrr subdirs-y += ../../x86/lapic @@ -8,4 +9,3 @@ subdirs-y += ../../x86/cache subdirs-y += ../../x86/smm subdirs-y += ../microcode subdirs-y += ../hyperthreading - diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index d16f85e..37b5848 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -2142,7 +2142,8 @@ #define PCI_DEVICE_ID_INTEL_82801DBM_EHCI 0x24cd
/* Intel 82801EB (ICH5) */ -#define PCI_DEVICE_ID_INTEL_82801EB_LAN 0x1051 +#define PCI_DEVICE_ID_INTEL_82801EB_LAN1 0x1050 +#define PCI_DEVICE_ID_INTEL_82801EB_LAN2 0x1051 #define PCI_DEVICE_ID_INTEL_82801EB_PCI 0x244e #define PCI_DEVICE_ID_INTEL_82801EB_LPC 0x24d0 #define PCI_DEVICE_ID_INTEL_82801EB_SATA 0x24d1 @@ -2157,7 +2158,8 @@ #define PCI_DEVICE_ID_INTEL_82801EB_USB4 0x24de
/* Intel 82801ER (ICH5R) */ -#define PCI_DEVICE_ID_INTEL_82801ER_LAN 0x1051 +#define PCI_DEVICE_ID_INTEL_82801ER_LAN1 0x1050 +#define PCI_DEVICE_ID_INTEL_82801ER_LAN2 0x1051 #define PCI_DEVICE_ID_INTEL_82801ER_PCI 0x244e #define PCI_DEVICE_ID_INTEL_82801ER_LPC 0x24d0 #define PCI_DEVICE_ID_INTEL_82801ER_USB1 0x24d2 diff --git a/src/mainboard/asrock/Kconfig b/src/mainboard/asrock/Kconfig index 1e4fff9..260f048 100644 --- a/src/mainboard/asrock/Kconfig +++ b/src/mainboard/asrock/Kconfig @@ -25,11 +25,14 @@ config BOARD_ASROCK_939A785GMH bool "939A785GMH/128M" config BOARD_ASROCK_E350M1 bool "E350M1" +config BOARD_ASROCK_P4I65GV + bool "P4i65GV"
endchoice
-source "src/mainboard/asrock/939a785gmh/Kconfig" +source "src/mainboard/asrock/939a785gmh/Kconfig" source "src/mainboard/asrock/e350m1/Kconfig" +source "src/mainboard/asrock/p4i65gv/Kconfig"
config MAINBOARD_VENDOR string diff --git a/src/mainboard/asrock/p4i65gv/Kconfig b/src/mainboard/asrock/p4i65gv/Kconfig new file mode 100644 index 0000000..21e2b3d --- /dev/null +++ b/src/mainboard/asrock/p4i65gv/Kconfig @@ -0,0 +1,53 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2009 Uwe Hermann uwe@hermann-uwe.de +## +## 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 +## +if BOARD_ASROCK_P4I65GV + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select ARCH_X86 + select CPU_INTEL_SOCKET_MPGA478 + select NORTHBRIDGE_INTEL_I865 + select SOUTHBRIDGE_INTEL_I82801EX + select SUPERIO_WINBOND_W83627HF + select HAVE_HARD_RESET +# select HAVE_PIRQ_TABLE + select UDELAY_TSC + select BOARD_ROMSIZE_KB_512 + select USE_WATCHDOG_ON_BOOT +# select HAVE_ACPI_TABLES +# select CACHE_AS_RAM # inherited from the socket option + +config MAINBOARD_DIR + string + default asrock/p4i65gv + +config MAINBOARD_PART_NUMBER + string + default "P4i65GV" + +config DCACHE_RAM_BASE + hex + default 0xfff00000 + +config DCACHE_RAM_SIZE + hex + default 0x8000 # ok? + +config IRQ_SLOT_COUNT + int + default 6 # no idea + +endif # BOARD_ASROCK_P4I65GV diff --git a/src/mainboard/asrock/p4i65gv/Makefile.inc b/src/mainboard/asrock/p4i65gv/Makefile.inc new file mode 100644 index 0000000..03e044d --- /dev/null +++ b/src/mainboard/asrock/p4i65gv/Makefile.inc @@ -0,0 +1 @@ +driver-y += rtl8139.c diff --git a/src/mainboard/asrock/p4i65gv/chip.h b/src/mainboard/asrock/p4i65gv/chip.h new file mode 100644 index 0000000..e77b136 --- /dev/null +++ b/src/mainboard/asrock/p4i65gv/chip.h @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 Uwe Hermann uwe@hermann-uwe.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +extern struct chip_operations mainboard_ops; +struct mainboard_config {}; diff --git a/src/mainboard/asrock/p4i65gv/devicetree.cb b/src/mainboard/asrock/p4i65gv/devicetree.cb new file mode 100644 index 0000000..992463c --- /dev/null +++ b/src/mainboard/asrock/p4i65gv/devicetree.cb @@ -0,0 +1,49 @@ +chip northbridge/intel/i865 + device lapic_cluster 0 on + chip cpu/intel/socket_mPGA478 + device lapic 0 on end + end + end + device pci_domain 0 on + device pci 0.0 on end # northbridge + device pci 0.1 off end # agp + device pci 0.2 on end # igd + device pnp 0.3 off end # csa + device pci 0.6 on end # overflow device + + chip southbridge/intel/i82801ex + device pci 1d.0 on end # uhci #1 + device pci 1d.1 on end # uhci #2 + device pci 1d.2 on end # uhci #3 + device pci 1d.3 on end # uhci #4 + device pci 1d.7 on end # ehci + device pci 1e.0 on # pci bridge + # 01:05.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+ [10ec:8139] (rev 10) + device pci 05.0 on end + end + + device pci 1f.0 on # lpc bridge + chip superio/winbond/w83627hf + device pnp 2e.0 off end # floppy + device pnp 2e.1 off end # parallel + device pnp 2e.2 on + io 0x60 = 0x3f8 + irq 0x70 = 4 + end # com1 + device pnp 2e.3 off end # com2 + device pnp 2e.5 on end # keyboard + device pnp 2e.6 off end # ir + device pnp 2e.7 on end # game/gpio 1 + device pnp 2e.8 on end # gpio 2 + device pnp 2e.9 on end # gpio 3 + device pnp 2e.a on end # acpi + device pnp 2e.b on end # hardware monitor + end # superio + end # 1f.0 + device pci 1f.1 on end # pata + device pci 1f.2 on end # sata + device pci 1f.3 on end # smbus + device pci 1f.5 off end # ac97 + end # southbridge + end # pci_domain +end # northbridge diff --git a/src/mainboard/asrock/p4i65gv/irq_tables.c b/src/mainboard/asrock/p4i65gv/irq_tables.c new file mode 100644 index 0000000..240ab23 --- /dev/null +++ b/src/mainboard/asrock/p4i65gv/irq_tables.c @@ -0,0 +1,63 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 200x TODO TODO@TODO + * + * 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 + */ + +#ifdef GETPIR /* TODO: Drop this when copying to coreboot. */ +#include "pirq_routing.h" /* TODO: Drop this when copying to coreboot. */ +#else /* TODO: Drop this when copying to coreboot. */ +#include <arch/pirq_routing.h> +#endif /* TODO: Drop this when copying to coreboot. */ + +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32 + 16 * 13, /* Max. number of devices on the bus */ + 0x00, /* Interrupt router bus */ + (0x1f << 3) | 0x0, /* Interrupt router dev */ + 0, /* IRQs devoted exclusively to PCI usage */ + 0x8086, /* Vendor */ + 0x24d0, /* Device */ + 0, /* Miniport */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0x3e, /* Checksum (has to be set to some value that + * would give 0 after the sum of all bytes + * for this structure (including checksum). + */ + { + /* bus, dev | fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */ + {0x01, (0x08 << 3) | 0x0, {{0x68, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x00, (0x1f << 3) | 0x0, {{0x62, 0xdcf8}, {0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x00, (0x1d << 3) | 0x0, {{0x60, 0xdcf8}, {0x63, 0xdcf8}, {0x62, 0xdcf8}, {0x6b, 0xdcf8}}, 0x0, 0x0}, + {0x00, (0x01 << 3) | 0x0, {{0x60, 0xdcf8}, {0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x00, (0x02 << 3) | 0x0, {{0x60, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x00, (0x03 << 3) | 0x0, {{0x00, 0x0000}, {0x62, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x01, (0x03 << 3) | 0x0, {{0x68, 0xdcf8}, {0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}}, 0x1, 0x0}, + {0x01, (0x01 << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}}, 0x2, 0x0}, + {0x01, (0x02 << 3) | 0x0, {{0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}, {0x6a, 0xdcf8}}, 0x3, 0x0}, + {0x01, (0x00 << 3) | 0x0, {{0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}}, 0x4, 0x0}, + {0x01, (0x04 << 3) | 0x0, {{0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}}, 0x5, 0x0}, + {0x01, (0x0a << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}}, 0x6, 0x0}, + {0x01, (0x05 << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + } +}; + +unsigned long write_pirq_routing_table(unsigned long addr) +{ + return copy_pirq_routing_table(addr); +} diff --git a/src/mainboard/asrock/p4i65gv/mainboard.c b/src/mainboard/asrock/p4i65gv/mainboard.c new file mode 100644 index 0000000..78aec29 --- /dev/null +++ b/src/mainboard/asrock/p4i65gv/mainboard.c @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 Uwe Hermann uwe@hermann-uwe.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <device/device.h> +#include "chip.h" + +struct chip_operations mainboard_ops = { + CHIP_NAME("ASRock P4i65GV Mainboard") +}; diff --git a/src/mainboard/asrock/p4i65gv/romstage.c b/src/mainboard/asrock/p4i65gv/romstage.c new file mode 100644 index 0000000..7f70ca0 --- /dev/null +++ b/src/mainboard/asrock/p4i65gv/romstage.c @@ -0,0 +1,84 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 Uwe Hermann uwe@hermann-uwe.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> +#include <device/pci_def.h> +#include <arch/io.h> +#include <device/pnp_def.h> +#include <arch/romcc_io.h> +#include <arch/hlt.h> +#include <stdlib.h> +#include <console/console.h> +#include <lib.h> +#include <cpu/x86/lapic.h> +#include "pc80/udelay_io.c" +//#include "lib/delay.c" +#include "cpu/x86/bist.h" + +//#include "southbridge/intel/i82801ex/i82801ex.h" +#include "southbridge/intel/i82801ex/early_smbus.c" +#include "northbridge/intel/i865/debug.c" +#include "northbridge/intel/i865/raminit.c" +//#include "northbridge/intel/i865/reset_test.c" +#include "northbridge/intel/i865/i865.h" +#include "superio/winbond/w83627hf/early_serial.c" +#include "watchdog.c" + +#define SERIAL_DEV PNP_DEV(0x2e, W83627HF_SP1) + +//int spd_read_byte(unsigned int device, unsigned int address) +//static inline int spd_read_byte(unsigned device, unsigned address) +//{ +// return smbus_read_byte(device, address); +//} + +void main(unsigned long bist) { + + // TODO + // copied from dell/s1850/romstage.c + /* + static const struct mem_controller memctrl[] = { + { + // node id? + .channel0 = { DIMM0, DIMM1, DIMM2, DIMM3, }, + .channel1 = { DIMM4, DIMM5, DIMM6, DIMM7, }, + } + }; +*/ + if (bist == 0) + enable_lapic(); + + w83627hf_set_clksel_48(SERIAL_DEV); + w83627hf_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE); + console_init(); + report_bist_failure(bist); + +// if (!bios_reset_detected()) /* board doesn't boot when using bios_rest_detected() */ +// { + enable_smbus(); + dump_spd_registers(); + + disable_ich5_watchdog(); + + // TODO: dual-channel, e.g.: + // sdram_initialize(ARRAY_SIZE(memctrl), memctrl); // copied from dell/s1850/romstage.c + sdram_initialize(); +// } +} diff --git a/src/mainboard/asrock/p4i65gv/rtl8139.c b/src/mainboard/asrock/p4i65gv/rtl8139.c new file mode 100644 index 0000000..d909af7 --- /dev/null +++ b/src/mainboard/asrock/p4i65gv/rtl8139.c @@ -0,0 +1,46 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 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; 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 + */ + +/* This code should work for all ICH* southbridges with a NIC. */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +static void nic_init(struct device *dev) +{ + printk(BIOS_DEBUG, "Initializing RTL8139 Fast Ethernet\n"); + // Nothing to do yet, but this has to be here to keep + // coreboot from trying to execute an option ROM. +} +static struct device_operations nic_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = nic_init, + .scan_bus = 0, +}; + +static const struct pci_driver rtl8139_nic __pci_driver = { + .ops = &nic_ops, + .vendor = PCI_VENDOR_ID_REALTEK, + .device = PCI_DEVICE_ID_REALTEK_8139, +}; diff --git a/src/mainboard/asrock/p4i65gv/watchdog.c b/src/mainboard/asrock/p4i65gv/watchdog.c new file mode 100644 index 0000000..8c7b0f6 --- /dev/null +++ b/src/mainboard/asrock/p4i65gv/watchdog.c @@ -0,0 +1,36 @@ +/* copied and adapted from src/mainboard/dell/s1850/watchdog.c */ + +#define ICH5_WDBASE 0x800 /* PMBASE */ +#define ICH5_GPIOBASE 0x480 + +static void disable_ich5_watchdog(void) +{ + /* FIXME move me somewhere more appropriate */ + device_t dev; + unsigned long value, base; + dev = pci_locate_device(PCI_ID(0x8086, 0x24d0), 0); /* LPC bridge */ + if (dev == PCI_DEV_INVALID) { + die("Missing ich5?"); + } + + /* Enable I/O space */ + value = pci_read_config16(dev, 0x04); /* PCICMD */ + value |= (1 << 10); /* reserved? */ + pci_write_config16(dev, 0x04, value); + + /* Set and enable acpibase */ + pci_write_config32(dev, 0x40, ICH5_WDBASE | 1); /* PMBASE */ + pci_write_config8(dev, 0x44, 0x10); /* ACPI_CNTL = ACPI_EN */ + base = ICH5_WDBASE + 0x60; /* TCO offset, ich5 datasheet ch9.11 */ + + /* Set bit 11 in TCO1_CNT */ + value = inw(base + 0x08); + value |= 1 << 11; /* enable TCO_TMR_HLT */ + outw(value, base + 0x08); + + /* Clear TCO timeout status */ + outw(0x0008, base + 0x04); /* TCO1_STS, raise bit 3: TIMEOUT */ + outw(0x0002, base + 0x06); /* TCO2_STS, raise bit 2: SECOND_TO_STS */ + + printk(BIOS_DEBUG, "Board-specific ICH5 watchdog disabled\n"); +} diff --git a/src/mainboard/asus/Kconfig b/src/mainboard/asus/Kconfig index 77b7997..1369a4b 100644 --- a/src/mainboard/asus/Kconfig +++ b/src/mainboard/asus/Kconfig @@ -55,7 +55,8 @@ config BOARD_ASUS_P2B_LS bool "P2B-LS" config BOARD_ASUS_P3B_F bool "P3B-F" - +config BOARD_ASUS_P4P800_VM + bool "P4P800-VM" endchoice
source "src/mainboard/asus/a8n_e/Kconfig" @@ -75,6 +76,7 @@ source "src/mainboard/asus/p2b-ds/Kconfig" source "src/mainboard/asus/p2b-f/Kconfig" source "src/mainboard/asus/p2b-ls/Kconfig" source "src/mainboard/asus/p3b-f/Kconfig" +source "src/mainboard/asus/p4p800-vm/Kconfig"
config MAINBOARD_VENDOR string diff --git a/src/mainboard/asus/p4p800-vm/Kconfig b/src/mainboard/asus/p4p800-vm/Kconfig new file mode 100644 index 0000000..ef93089 --- /dev/null +++ b/src/mainboard/asus/p4p800-vm/Kconfig @@ -0,0 +1,53 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2009 Uwe Hermann uwe@hermann-uwe.de +## +## 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 +## +if BOARD_ASUS_P4P800_VM + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select ARCH_X86 + select CPU_INTEL_SOCKET_MPGA478 + select NORTHBRIDGE_INTEL_I865 + select SOUTHBRIDGE_INTEL_I82801EX + select SUPERIO_WINBOND_W83627THG + select HAVE_HARD_RESET +# select HAVE_PIRQ_TABLE + select UDELAY_TSC + select BOARD_ROMSIZE_KB_512 + select USE_WATCHDOG_ON_BOOT +# select HAVE_ACPI_TABLES +# select CACHE_AS_RAM # inherited from the socket option + +config MAINBOARD_DIR + string + default asus/p4p800-vm + +config MAINBOARD_PART_NUMBER + string + default "P4P800-VM" + +config DCACHE_RAM_BASE + hex + default 0xfff00000 + +config DCACHE_RAM_SIZE + hex + default 0x8000 # ok? + +config IRQ_SLOT_COUNT + int + default 6 # no idea + +endif # BOARD_ASUS_P4P800_VM diff --git a/src/mainboard/asus/p4p800-vm/Makefile.inc b/src/mainboard/asus/p4p800-vm/Makefile.inc new file mode 100644 index 0000000..93aefe9 --- /dev/null +++ b/src/mainboard/asus/p4p800-vm/Makefile.inc @@ -0,0 +1 @@ +driver-y += e100.c diff --git a/src/mainboard/asus/p4p800-vm/chip.h b/src/mainboard/asus/p4p800-vm/chip.h new file mode 100644 index 0000000..e77b136 --- /dev/null +++ b/src/mainboard/asus/p4p800-vm/chip.h @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 Uwe Hermann uwe@hermann-uwe.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +extern struct chip_operations mainboard_ops; +struct mainboard_config {}; diff --git a/src/mainboard/asus/p4p800-vm/devicetree.cb b/src/mainboard/asus/p4p800-vm/devicetree.cb new file mode 100644 index 0000000..cf80f53 --- /dev/null +++ b/src/mainboard/asus/p4p800-vm/devicetree.cb @@ -0,0 +1,49 @@ +chip northbridge/intel/i865 + device lapic_cluster 0 on + chip cpu/intel/socket_mPGA478 + device lapic 0 on end + end + end + device pci_domain 0 on + device pci 0.0 on end # northbridge + device pci 0.1 off end # agp + device pci 0.2 on end # igd + device pnp 0.3 off end # csa + device pci 0.6 on end # overflow device + + chip southbridge/intel/i82801ex + device pci 1d.0 on end # uhci #1 + device pci 1d.1 on end # uhci #2 + device pci 1d.2 on end # uhci #3 + device pci 1d.3 on end # uhci #4 + device pci 1d.7 on end # ehci + device pci 1e.0 on # pci bridge + # 01:08.0 Ethernet controller: Intel Corporation 82562EZ 10/100 Ethernet Controller (rev 02) + device pci 08.0 on end + end + + device pci 1f.0 on # lpc bridge + chip superio/winbond/w83627thg + device pnp 2e.0 off end # floppy + device pnp 2e.1 off end # parallel + device pnp 2e.2 on + io 0x60 = 0x3f8 + irq 0x70 = 4 + end # com1 + device pnp 2e.3 off end # com2 + device pnp 2e.5 on end # keyboard + device pnp 2e.6 off end # ir + device pnp 2e.7 on end # game/gpio 1 + device pnp 2e.8 on end # gpio 2 + device pnp 2e.9 on end # gpio 3 + device pnp 2e.a on end # acpi + device pnp 2e.b on end # hardware monitor + end # superio + end # 1f.0 + device pci 1f.1 on end # pata + device pci 1f.2 on end # sata + device pci 1f.3 on end # smbus + device pci 1f.5 off end # ac97 + end # southbridge + end # pci_domain +end # northbridge diff --git a/src/mainboard/asus/p4p800-vm/e100.c b/src/mainboard/asus/p4p800-vm/e100.c new file mode 100644 index 0000000..d3c0e07 --- /dev/null +++ b/src/mainboard/asus/p4p800-vm/e100.c @@ -0,0 +1,46 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 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; 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 + */ + +/* This code should work for all ICH* southbridges with a NIC. */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> + +static void nic_init(struct device *dev) +{ + printk(BIOS_DEBUG, "Initializing Intel 82562EZ 10/100 Ethernet\n"); + // Nothing to do yet, but this has to be here to keep + // coreboot from trying to execute an option ROM. +} +static struct device_operations nic_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = nic_init, + .scan_bus = 0, +}; + +static const struct pci_driver intel_e100_nic __pci_driver = { + .ops = &nic_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801EB_LAN1, /* 8086:1050 */ +}; diff --git a/src/mainboard/asus/p4p800-vm/irq_tables.c b/src/mainboard/asus/p4p800-vm/irq_tables.c new file mode 100644 index 0000000..240ab23 --- /dev/null +++ b/src/mainboard/asus/p4p800-vm/irq_tables.c @@ -0,0 +1,63 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 200x TODO TODO@TODO + * + * 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 + */ + +#ifdef GETPIR /* TODO: Drop this when copying to coreboot. */ +#include "pirq_routing.h" /* TODO: Drop this when copying to coreboot. */ +#else /* TODO: Drop this when copying to coreboot. */ +#include <arch/pirq_routing.h> +#endif /* TODO: Drop this when copying to coreboot. */ + +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32 + 16 * 13, /* Max. number of devices on the bus */ + 0x00, /* Interrupt router bus */ + (0x1f << 3) | 0x0, /* Interrupt router dev */ + 0, /* IRQs devoted exclusively to PCI usage */ + 0x8086, /* Vendor */ + 0x24d0, /* Device */ + 0, /* Miniport */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0x3e, /* Checksum (has to be set to some value that + * would give 0 after the sum of all bytes + * for this structure (including checksum). + */ + { + /* bus, dev | fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */ + {0x01, (0x08 << 3) | 0x0, {{0x68, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x00, (0x1f << 3) | 0x0, {{0x62, 0xdcf8}, {0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x00, (0x1d << 3) | 0x0, {{0x60, 0xdcf8}, {0x63, 0xdcf8}, {0x62, 0xdcf8}, {0x6b, 0xdcf8}}, 0x0, 0x0}, + {0x00, (0x01 << 3) | 0x0, {{0x60, 0xdcf8}, {0x61, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x00, (0x02 << 3) | 0x0, {{0x60, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x00, (0x03 << 3) | 0x0, {{0x00, 0x0000}, {0x62, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + {0x01, (0x03 << 3) | 0x0, {{0x68, 0xdcf8}, {0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}}, 0x1, 0x0}, + {0x01, (0x01 << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}}, 0x2, 0x0}, + {0x01, (0x02 << 3) | 0x0, {{0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}, {0x6a, 0xdcf8}}, 0x3, 0x0}, + {0x01, (0x00 << 3) | 0x0, {{0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}}, 0x4, 0x0}, + {0x01, (0x04 << 3) | 0x0, {{0x69, 0xdcf8}, {0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}}, 0x5, 0x0}, + {0x01, (0x0a << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x68, 0xdcf8}, {0x69, 0xdcf8}}, 0x6, 0x0}, + {0x01, (0x05 << 3) | 0x0, {{0x6a, 0xdcf8}, {0x6b, 0xdcf8}, {0x00, 0x0000}, {0x00, 0x0000}}, 0x0, 0x0}, + } +}; + +unsigned long write_pirq_routing_table(unsigned long addr) +{ + return copy_pirq_routing_table(addr); +} diff --git a/src/mainboard/asus/p4p800-vm/mainboard.c b/src/mainboard/asus/p4p800-vm/mainboard.c new file mode 100644 index 0000000..5b47989 --- /dev/null +++ b/src/mainboard/asus/p4p800-vm/mainboard.c @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 Uwe Hermann uwe@hermann-uwe.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <device/device.h> +#include "chip.h" + +struct chip_operations mainboard_ops = { + CHIP_NAME("ASUS P4P800-VM Mainboard") +}; diff --git a/src/mainboard/asus/p4p800-vm/romstage.c b/src/mainboard/asus/p4p800-vm/romstage.c new file mode 100644 index 0000000..fad3aca --- /dev/null +++ b/src/mainboard/asus/p4p800-vm/romstage.c @@ -0,0 +1,84 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 Uwe Hermann uwe@hermann-uwe.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> +#include <device/pci_def.h> +#include <arch/io.h> +#include <device/pnp_def.h> +#include <arch/romcc_io.h> +#include <arch/hlt.h> +#include <stdlib.h> +#include <console/console.h> +#include <lib.h> +#include <cpu/x86/lapic.h> +#include "pc80/udelay_io.c" +//#include "lib/delay.c" +#include "cpu/x86/bist.h" + +//#include "southbridge/intel/i82801ex/i82801ex.h" +#include "southbridge/intel/i82801ex/early_smbus.c" +#include "northbridge/intel/i865/debug.c" +#include "northbridge/intel/i865/raminit.c" +//#include "northbridge/intel/i865/reset_test.c" +#include "northbridge/intel/i865/i865.h" +#include "superio/winbond/w83627thg/early_serial.c" +#include "watchdog.c" + +#define SERIAL_DEV PNP_DEV(0x2e, W83627THG_SP1) + +//int spd_read_byte(unsigned int device, unsigned int address) +//static inline int spd_read_byte(unsigned device, unsigned address) +//{ +// return smbus_read_byte(device, address); +//} + +void main(unsigned long bist) { + + // TODO + // copied from dell/s1850/romstage.c + /* + static const struct mem_controller memctrl[] = { + { + // node id? + .channel0 = { DIMM0, DIMM1, DIMM2, DIMM3, }, + .channel1 = { DIMM4, DIMM5, DIMM6, DIMM7, }, + } + }; +*/ + if (bist == 0) + enable_lapic(); + + w83627thg_set_clksel_48(SERIAL_DEV); + w83627thg_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE); + console_init(); + report_bist_failure(bist); + +// if (!bios_reset_detected()) /* board doesn't boot when using bios_rest_detected() */ +// { + enable_smbus(); + dump_spd_registers(); + + disable_ich5_watchdog(); + + // TODO: dual-channel, e.g.: + // sdram_initialize(ARRAY_SIZE(memctrl), memctrl); // copied from dell/s1850/romstage.c + sdram_initialize(); +// } +} diff --git a/src/mainboard/asus/p4p800-vm/watchdog.c b/src/mainboard/asus/p4p800-vm/watchdog.c new file mode 100644 index 0000000..8c7b0f6 --- /dev/null +++ b/src/mainboard/asus/p4p800-vm/watchdog.c @@ -0,0 +1,36 @@ +/* copied and adapted from src/mainboard/dell/s1850/watchdog.c */ + +#define ICH5_WDBASE 0x800 /* PMBASE */ +#define ICH5_GPIOBASE 0x480 + +static void disable_ich5_watchdog(void) +{ + /* FIXME move me somewhere more appropriate */ + device_t dev; + unsigned long value, base; + dev = pci_locate_device(PCI_ID(0x8086, 0x24d0), 0); /* LPC bridge */ + if (dev == PCI_DEV_INVALID) { + die("Missing ich5?"); + } + + /* Enable I/O space */ + value = pci_read_config16(dev, 0x04); /* PCICMD */ + value |= (1 << 10); /* reserved? */ + pci_write_config16(dev, 0x04, value); + + /* Set and enable acpibase */ + pci_write_config32(dev, 0x40, ICH5_WDBASE | 1); /* PMBASE */ + pci_write_config8(dev, 0x44, 0x10); /* ACPI_CNTL = ACPI_EN */ + base = ICH5_WDBASE + 0x60; /* TCO offset, ich5 datasheet ch9.11 */ + + /* Set bit 11 in TCO1_CNT */ + value = inw(base + 0x08); + value |= 1 << 11; /* enable TCO_TMR_HLT */ + outw(value, base + 0x08); + + /* Clear TCO timeout status */ + outw(0x0008, base + 0x04); /* TCO1_STS, raise bit 3: TIMEOUT */ + outw(0x0002, base + 0x06); /* TCO2_STS, raise bit 2: SECOND_TO_STS */ + + printk(BIOS_DEBUG, "Board-specific ICH5 watchdog disabled\n"); +} diff --git a/src/northbridge/intel/Kconfig b/src/northbridge/intel/Kconfig index 1809d11..e5c8ed5 100644 --- a/src/northbridge/intel/Kconfig +++ b/src/northbridge/intel/Kconfig @@ -8,5 +8,6 @@ source src/northbridge/intel/i440lx/Kconfig source src/northbridge/intel/i82810/Kconfig source src/northbridge/intel/i82830/Kconfig source src/northbridge/intel/i855/Kconfig +source src/northbridge/intel/i865/Kconfig source src/northbridge/intel/i945/Kconfig source src/northbridge/intel/sch/Kconfig diff --git a/src/northbridge/intel/Makefile.inc b/src/northbridge/intel/Makefile.inc index 0d116d0..9d333b6 100644 --- a/src/northbridge/intel/Makefile.inc +++ b/src/northbridge/intel/Makefile.inc @@ -8,6 +8,7 @@ subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I440LX) += i440lx subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I82810) += i82810 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I82830) += i82830 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I855) += i855 +subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I865) += i865 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I945GC) += i945 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_I945GM) += i945 subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SCH) += sch diff --git a/src/northbridge/intel/i865/Kconfig b/src/northbridge/intel/i865/Kconfig new file mode 100644 index 0000000..944f701 --- /dev/null +++ b/src/northbridge/intel/i865/Kconfig @@ -0,0 +1,25 @@ +config NORTHBRIDGE_INTEL_I865 + bool + select HAVE_DEBUG_RAM_SETUP +choice +prompt "Onboard graphics" + default I865_VIDEO_MB_8MB + depends on NORTHBRIDGE_INTEL_I865 + +config I865_VIDEO_MB_OFF + bool "Disabled, 0KB" +config I865_VIDEO_MB_1MB + bool "Enabled, 1MB" +config I865_VIDEO_MB_8MB + bool "Enabled, 8MB" +config I865_VIDEO_MB_16MB + bool "Enabled, 16MB" +endchoice + +config VIDEO_MB + int + default 0 if I865_VIDEO_MB_OFF + default 1 if I865_VIDEO_MB_1MB + default 8 if I865_VIDEO_MB_8MB + default 16 if I865_VIDEO_MB_16MB + depends on NORTHBRIDGE_INTEL_I865 diff --git a/src/northbridge/intel/i865/Makefile.inc b/src/northbridge/intel/i865/Makefile.inc new file mode 100644 index 0000000..8cec43f --- /dev/null +++ b/src/northbridge/intel/i865/Makefile.inc @@ -0,0 +1,2 @@ +ramstage-y += northbridge.c +#romstage-y += early_init.c diff --git a/src/northbridge/intel/i865/TODO b/src/northbridge/intel/i865/TODO new file mode 100644 index 0000000..2f28af0 --- /dev/null +++ b/src/northbridge/intel/i865/TODO @@ -0,0 +1,16 @@ +TODO (probably incomplete) + +raminit.c: + * re-use the mchbar macro from i945 and read/write from/to it like its raminit code does + * GPL headers everywhere + * includes (is assert.h really needed?) + * set TOUD (from northbridge.c?) + * set SMFREQ and FSBFREQ (in GMCHCFG) (from northbridge.c?)? + * AGP (device 1) code + * VGA/IGD (device 2) code + * CSA (device 3) code? + * clean up/trim northbridge_set_registers() + * dual-channel code (and don't forget romstage.c) + +DONE +* raise bits 0 (IOAE, I/O access enable) and 1 (MAE, memory access enable) in PCICMD6 (from northbridge.c?) diff --git a/src/northbridge/intel/i865/chip.h b/src/northbridge/intel/i865/chip.h new file mode 100644 index 0000000..6e7b21e --- /dev/null +++ b/src/northbridge/intel/i865/chip.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2006 Jon Dufresne jon.dufresne@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 + */ + +struct northbridge_intel_i865_config +{ +}; + +extern struct chip_operations northbridge_intel_i865_ops; diff --git a/src/northbridge/intel/i865/debug.c b/src/northbridge/intel/i865/debug.c new file mode 100644 index 0000000..a7935ce --- /dev/null +++ b/src/northbridge/intel/i865/debug.c @@ -0,0 +1,139 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2003 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <spd.h> +static void print_debug_pci_dev(unsigned dev) { + print_debug("PCI: "); + print_debug_hex8((dev >> 20) & 0xff); + print_debug_char(':'); + print_debug_hex8((dev >> 15) & 0x1f); + print_debug_char('.'); + print_debug_hex8((dev >> 12) & 0x07); +} +static inline void print_pci_devices(void) { + device_t dev; + for(dev = PCI_DEV(0, 0, 0); + dev <= PCI_DEV(0, 0x1f, 0x7); + dev += PCI_DEV(0,0,1)) { + uint32_t id; + id = pci_read_config32(dev, PCI_VENDOR_ID); + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0x0000)) { + continue; + } + print_debug_pci_dev(dev); + print_debug("\n"); + } +} +static void dump_pci_device(unsigned dev) { + int i; + print_debug_pci_dev(dev); + print_debug("\n"); + for(i = 0; i <= 255; i++) { + unsigned char val; + if ((i & 0x0f) == 0) { + print_debug_hex8(i); + print_debug_char(':'); + } + val = pci_read_config8(dev, i); + print_debug_char(' '); + print_debug_hex8(val); + if ((i & 0x0f) == 0x0f) { + print_debug("\n"); + } + } +} +static inline void dump_pci_devices(void) { + device_t dev; + for(dev = PCI_DEV(0, 0, 0); + dev <= PCI_DEV(0, 0x1f, 0x7); + dev += PCI_DEV(0,0,1)) { + uint32_t id; + id = pci_read_config32(dev, PCI_VENDOR_ID); + if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0xffff) || + (((id >> 16) & 0xffff) == 0x0000)) { + continue; + } + dump_pci_device(dev); + } +} +static inline void dump_spd_registers(void) { + int i; + print_debug("\n"); + for(i = 0; i < 2; i++) { + unsigned device; + device = DIMM0 + i; + if (device) { + int j; + print_debug("dimm: "); + print_debug_hex8(i); + print_debug(".0: "); + print_debug_hex8(device); + for(j = 0; j < 256; j++) { + int status; + unsigned char byte; + if ((j & 0xf) == 0) { + print_debug("\n"); + print_debug_hex8(j); + print_debug(": "); + } + status = smbus_read_byte(device, j); + if (status < 0) { + print_debug("bad device\n"); + break; + } + byte = status & 0xff; + print_debug_hex8(byte); + print_debug_char(' '); + } + print_debug("\n"); + } + } +} +static inline void dump_smbus_registers(void) { + int i; + print_debug("\n"); + for(i = 1; i < 0x80; i++) { + unsigned device; + device = i; + int j; + print_debug("smbus: "); + print_debug_hex8(device); + for(j = 0; j < 256; j++) { + int status; + unsigned char byte; + if ((j & 0xf) == 0) { + print_debug("\n"); + print_debug_hex8(j); + print_debug(": "); + } + status = smbus_read_byte(device, j); + if (status < 0) { + print_debug("bad device\n"); + break; + } + byte = status & 0xff; + print_debug_hex8(byte); + print_debug_char(' '); + } + print_debug("\n"); + } +} diff --git a/src/northbridge/intel/i865/i865.h b/src/northbridge/intel/i865/i865.h new file mode 100644 index 0000000..51cf0bc --- /dev/null +++ b/src/northbridge/intel/i865/i865.h @@ -0,0 +1,89 @@ +/* TODO: + * AGP #defines + * GPL header + */ + +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Travelping GmbH info@travelping.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* size, default value */ +/* DRAM Controller (device 0) */ +#define APBASE 0x10 /* 32 bit, 0x8 */ +// #define AGPM 0x51 /* 8 bit, 0x0 */ +// #define ESMRAMC 0x9e /* 8 bit, 0x38 */ +// #define ACAPID 0xa0 /* 32bit, 0x300002 (RO) */ +// #define AGPSTAT 0xa4 /* 32bit, AGP 2.0: 0x1f004217 (RO) or AGP 3.0: 0x1f004a13 (RO) */ +// #define AGPCMD 0xa8 /* 32bit, AGP 2.0: 0x0 or AGP 3.0: 0xa00 */ +// #define AGPCTRL 0xb0 /* 32bit, 0x0 */ +#define AMTT 0xbc /* 8 bit, 0x10 */ +#define APSIZE 0xb4 /* 8 bit, 0x0 */ +// #define ATTBASE 0xb8 /* 32 bit, 0x0 */ +#define TOUD 0xc4 /* 16 bit, 0x400 */ +#define GMCHCFG 0xc6 /* 16 bit, 0x0 */ +#define ERRSTS 0xc8 /* 16 bit, 0x0 */ +// #define ERRCMD 0xca /* 16 bit, 0x0 */ +// #define FDHC 0x97 /* 8 bit, 0x0 */ +// #define FPLLCONT 0x60 /* 8 bit, 0x0 */ +#define GC 0x52 /* 8 bit (looks wrong), 0x1000 */ +#define LPTT 0xbd /* 8 bit, 0x10 */ +#define PCISTS 0x10 /* 16 bit, 0x90 */ +// #define SMRAM 0x9D /* 8 bit, 0x2 */ +#define SVID 0x2c /* 16 bit, 0x0 */ +#define SID 0x2e /* 16 bit, 0x0 */ +// #define CSABCONT 0x53 /* 8 bit, 0x0 */ +#define VID 0x0 /* 16 bit, 0x8086 */ +#define DID 0x2 /* 16 bit, 0x2570 */ +/* PCI-to-AGP bridge (device 1) */ +// #define PCICMD1 0x04 /* 16 bit, 0x0 */ +// #define SMLT1 0x0d /* 8 bit, 0x0 */ +// #define SBUSN1 0x19 /* 8 bit, 0x0 */ +// #define SUBUSN1 0x1a /* 8 bit, 0x0 */ +// #define PMBASE1 0x24 /* 16 bit, 0xfff0 */ +// #define PMLIMIT1 0x26 /* 16 bit, 0x0 */ +// #define BCTRL1 0x3e /* 8 bit, 0x0 */ +// #define ERRCMD1 0x40 /* 8 bit, 0x0 */ + +/* Integrated Graphics Device (device 2) */ +// #define PCICMD2 0x04 /* 16 bit, 0x0 */ +// #define GMADR 0x10 /* 32 bit, 0x8 */ +// #define MMADR 0x14 /* 32 bit, 0x0 */ +// #define IOBAR 0x18 /* 32 bit, 0x1 */ +// #define SVID2 0x2c /* 16 bit, 0x0 */ +// #define SID2 0x2e /* 16 bit, 0x0 */ +// #define INTRLINE 0x3c /* 8 bit, 0x0 */ +// #define PMCS 0xd4 /* 16 bit, 0x0 */ +// #define SWSMI 0xe0 /* 16 bit, 0x0 */ + +/* PCI-to-CSA bridge (device 3) */ +// #define PCICMD3 0x04 /* 16 bit, 0x0 */ +// #define IOBASE3 0x1c /* 8 bit, 0xf0 */ +// #define IOLIMIT3 0x1d /* 8 bit, 0x0 */ +// #define MBASE3 0x20 /* 16 bit, 0xfff0 */ +// #define MLIMIT3 0x22 /* 16 bit, 0x0 */ +// #define PMBASE3 0x24 /* 16 bit, 0xfff0 */ +// #define PMLIMIT3 0x26 /* 16 bit, 0x0 */ +// #define BCTRL3 0x3e /* 8 bit, 0x0 */ +// #define CSACNTRL 0x50 /* 32 bit, 0xe042802 */ + +/* Overflow device (device 6) */ +#define PCICMD6 0x04 /* 16 bit (looks wrong), 0x0 */ +#define BAR6 0x10 /* 32 bit, 0x0 */ +// #define SVID6 0x2c /* 16 bit, 0x0 */ +// #define SID6 0x2e /* 16 bit, 0x0 */ diff --git a/src/northbridge/intel/i865/northbridge.c b/src/northbridge/intel/i865/northbridge.c new file mode 100644 index 0000000..c249be3 --- /dev/null +++ b/src/northbridge/intel/i865/northbridge.c @@ -0,0 +1,171 @@ +/* TODO: + * CSA (device 3) code + * set all subsytem IDs (SID*, SVID*) + */ + + /* + * This file is part of the coreboot project. + * + * Copyright (C) 2003 Ronald G. Minnich + * Copyright (C) 2003-2004 Eric W. Biederman + * Copyright (C) 2006 Jon Dufresne jon.dufresne@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 + */ + +#include <console/console.h> +#include <arch/io.h> +#include <stdint.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <stdlib.h> +#include <string.h> +#include <bitops.h> +#include <cpu/x86/cache.h> +#include <cpu/cpu.h> +#include "chip.h" +#include "i865.h" +#include "raminit.h" + +static void northbridge_init(device_t dev) +{ + printk(BIOS_SPEW, "Northbridge init\n"); +} + +static struct device_operations northbridge_operations = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = northbridge_init, + .enable = 0, + .ops_pci = 0, +}; + +static const struct pci_driver northbridge_driver __pci_driver = { + .ops = &northbridge_operations, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x2570, +}; + +#if CONFIG_WRITE_HIGH_TABLES==1 +#define HIGH_TABLES_SIZE 64 // maximum size of high tables in KB +extern uint64_t high_tables_base, high_tables_size; +#endif +static void pci_domain_set_resources(device_t dev) +{ + device_t mc_dev; + uint32_t pci_tolm; + + printk(BIOS_DEBUG, "Entered with dev vid = %x\n", dev->vendor); + printk(BIOS_DEBUG, "Entered with dev did = %x\n", dev->device); + + pci_tolm = find_pci_tolm(dev->link_list); + mc_dev = dev->link_list->children->sibling; + printk(BIOS_DEBUG, "MC dev vendor = %x\n", mc_dev->vendor); + printk(BIOS_DEBUG, "MC dev device = %x\n", mc_dev->device); + + if (mc_dev) { + /* Figure out which areas are/should be occupied by RAM. + * This is all computed in kilobytes and converted to/from + * the memory controller right at the edges. + * Having different variables in different units is + * too confusing to get right. Kilobytes are good up to + * 4 Terabytes of RAM... + */ + unsigned long tomk, tolmk; + int idx; + + /* Get the value of the highest DRB. This tells the end of + * the physical memory. The units are ticks of 64 MB + * i.e. 1 means 64 MB. + */ + //tomk = (unsigned long)pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), DRB + 7); +// tomk = BAR6_8(DRB + 7); + tomk = MCHBAR8(DRB + 7); + tomk = tomk * 64 * 1024; + /* add vga_mem detection */ + tomk = tomk - 16 * 1024; // 16 MB, graphics mode select (GMS) + /* Compute the top of Low memory */ + tolmk = pci_tolm >> 10; + if (tolmk >= tomk) { + /* The PCI hole does not overlap memory + */ + tolmk = tomk; + } + /* Write the ram configuration registers, + * preserving the reserved bits. + */ + + /* Report the memory regions */ + printk(BIOS_DEBUG, "tomk = %ld\n", tomk); + printk(BIOS_DEBUG, "tolmk = %ld\n", tolmk); + + idx = 10; + /* avoid pam region */ + ram_resource(dev, idx++, 0, 640); + /* ram_resource(dev, idx++, 1024, tolmk - 1024); */ + ram_resource(dev, idx++, 768, tolmk - 768); + +#if CONFIG_WRITE_HIGH_TABLES==1 + /* Leave some space for ACPI, PIRQ and MP tables */ + high_tables_base = (tomk - HIGH_TABLES_SIZE) * 1024; + high_tables_size = HIGH_TABLES_SIZE * 1024; +#endif + } + assign_resources(dev->link_list); +} + +static struct device_operations pci_domain_ops = { + .read_resources = pci_domain_read_resources, + .set_resources = pci_domain_set_resources, + .enable_resources = NULL, + .init = NULL, + .scan_bus = pci_domain_scan_bus, +}; + +static void cpu_bus_init(device_t dev) +{ + initialize_cpus(dev->link_list); +} + +static void cpu_bus_noop(device_t dev) +{ +} + +static struct device_operations cpu_bus_ops = { + .read_resources = cpu_bus_noop, + .set_resources = cpu_bus_noop, + .enable_resources = cpu_bus_noop, + .init = cpu_bus_init, + .scan_bus = 0, +}; + +static void enable_dev(struct device *dev) +{ + /* Set the operations if it is a special bus type */ + if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) { + dev->ops = &pci_domain_ops; + pci_set_method(dev); + } + else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) { + dev->ops = &cpu_bus_ops; + } +} + +struct chip_operations northbridge_intel_i865_ops = { + CHIP_NAME("Intel 865 Northbridge") + .enable_dev = enable_dev, +}; diff --git a/src/northbridge/intel/i865/raminit.c b/src/northbridge/intel/i865/raminit.c new file mode 100644 index 0000000..91e3144 --- /dev/null +++ b/src/northbridge/intel/i865/raminit.c @@ -0,0 +1,1031 @@ +#include <spd.h> +#include <stdlib.h> +#include <sdram_mode.h> + +#include "i865.h" +#include "raminit.h" + +struct dimm_size { + unsigned int side1; + unsigned int side2; +}; + +static const uint32_t refresh_frequency[] = { + /* Relative frequency (array value) of each E7501 Refresh Mode Select + * (RMS) value (array index) + * 0 == least frequent refresh (longest interval between refreshes) + * [0] disabled -> 0 + * [1] 15.6 usec -> 2 + * [2] 7.8 usec -> 3 + * [3] 64 usec -> 1 + * [4] reserved -> 0 + * [5] reserved -> 0 + * [6] reserved -> 0 + * [7] 64 clocks -> 4 + */ + 0, 2, 3, 1, 0, 0, 0, 4 +}; + +static const uint32_t refresh_rate_map[] = { + /* Map the JEDEC spd refresh rates (array index) to i855 Refresh Mode + * Select values (array value) + * These are all the rates defined by JESD21-C Appendix D, Rev. 1.0 + * The i855 supports only 15.6 us (1), 7.8 us (2) and + * 64 clock (481 ns) (7) refresh. + * [0] == 15.625 us -> 15.6 us + * [1] == 3.9 us -> 481 ns + * [2] == 7.8 us -> 7.8 us + * [3] == 31.3 us -> 15.6 us + * [4] == 62.5 us -> 15.6 us + * [5] == 125 us -> 15.6 us + */ + 1, 7, 2, 1, 1, 1 +}; + +#define MAX_SPD_REFRESH_RATE ((sizeof(refresh_rate_map) / sizeof(uint32_t)) - 1) + +static inline int spd_read_byte(unsigned device, unsigned address) +//static int spd_read_byte(unsigned device, unsigned address) +{ + return smbus_read_byte(device, address); +} + +static void set_initialization_complete(void) +{ + printk(BIOS_DEBUG, "Setting initialization complete (DRC bit 29)\n"); + MCHBAR32(DRC) |= RAM_INITIALIZATION_COMPLETE; +} + +//static void do_ram_command(u32 command) +static void do_ram_command(uint8_t command, uint16_t jedec_mode_bits) +{ + int i; + u32 reg32; +// uint8_t dimm_start_32M_multiple = 0; + uint8_t dimm_start_64M_multiple = 0; + uint16_t i855_mode_bits = jedec_mode_bits; + + /* Configure the RAM command. */ +// reg32 = pci_read_config32(NORTHBRIDGE_MMC, DRC); + reg32 = MCHBAR32(DRC); + reg32 &= ~(7 << 4); + reg32 |= (command << 4); + printk(BIOS_DEBUG, " Sending RAM command 0x%08x\n", reg32); +// pci_write_config32(NORTHBRIDGE_MMC, DRC, reg32); + MCHBAR32(DRC) = reg32; + + // RAM_COMMAND_NORMAL is an exception. + // It affects only the memory controller and does not need to be "sent" to the DIMMs. + + if (command != RAM_COMMAND_NORMAL) { + + // Send the command to all DIMMs by accessing a memory location within each + // NOTE: for mode select commands, some of the location address bits + // are part of the command + + // Map JEDEC mode bits to i855 + if (command == RAM_COMMAND_MRS || command == RAM_COMMAND_EMRS) { + /* Host address lines [13:3] map to DIMM address lines [11, 9:0] */ + // i855_mode_bits = ((jedec_mode_bits & 0x800) << (13 - 11)) | ((jedec_mode_bits & 0x3ff) << (12 - 9)); + /* Host address lines [13:3] map to DIMM address lines [5:1] */ + // i855_mode_bits = ((jedec_mode_bits & 0x800) << (13 - 11)) | ((jedec_mode_bits & 0x3ff) << (6 - 1)); + i855_mode_bits = ((jedec_mode_bits & 0x800) << (13 - 11)) | ((jedec_mode_bits & 0x3f) << (6 - 1)); + } + + for (i = 0; i < (DIMM_SOCKETS * 2); ++i) { +// uint8_t dimm_end_32M_multiple = pci_read_config8(NORTHBRIDGE_MMC, DRB + i); + /* i865 uses a granularity of 64 megabyte */ + uint8_t dimm_end_64M_multiple = MCHBAR8(DRB + i); +// if (dimm_end_32M_multiple > dimm_start_32M_multiple) { + if (dimm_end_64M_multiple > dimm_start_64M_multiple) { + +// uint32_t dimm_start_address = dimm_start_32M_multiple << 25; + uint32_t dimm_start_address = dimm_start_64M_multiple << 25; + printk(BIOS_DEBUG, " Sending RAM command to 0x%08x\n", dimm_start_address + i855_mode_bits); + //read32(dimm_start_address + i855_mode_bits); + printk(BIOS_DEBUG, " /* skipping read32() */\n"); + printk(BIOS_DEBUG, " Sent. dimm_start_address = 0x%x and i855_mode_bits = 0x%x\n", dimm_start_address, i855_mode_bits); + + // Set the start of the next DIMM +// dimm_start_32M_multiple = dimm_end_32M_multiple; + dimm_start_64M_multiple = dimm_end_64M_multiple; + } + } + } +} + +static void sdram_enable(void) +{ + int i; + + print_debug("Ram enable 1\n"); + delay(); + delay(); + + /* NOP command */ + printk(BIOS_DEBUG, " NOP\n"); + do_ram_command(RAM_COMMAND_NOP, 0); + delay(); + delay(); + delay(); + + /* Pre-charge all banks (at least 200 us after NOP) */ + printk(BIOS_DEBUG, " Pre-charging all banks\n"); + do_ram_command(RAM_COMMAND_PRECHARGE, 0); + delay(); + delay(); + delay(); + + printk(BIOS_DEBUG, "Ram enable 4\n"); + do_ram_command(RAM_COMMAND_EMRS, SDRAM_EXTMODE_DLL_ENABLE); + delay(); + delay(); + delay(); + + print_debug("Ram enable 5\n"); + do_ram_command(RAM_COMMAND_MRS, VG85X_MODE | SDRAM_MODE_DLL_RESET); + + print_debug("Ram enable 6\n"); + do_ram_command(RAM_COMMAND_PRECHARGE, 0); + delay(); + delay(); + delay(); + + /* 8 CBR refreshes (Auto Refresh) */ + printk(BIOS_DEBUG, " 8 CBR refreshes\n"); + for(i = 0; i < 8; i++) { + do_ram_command(RAM_COMMAND_CBR, 0); + delay(); + delay(); + delay(); + } + + printk(BIOS_DEBUG, "Ram enable 8\n"); + do_ram_command(RAM_COMMAND_MRS, VG85X_MODE | SDRAM_MODE_NORMAL); + + /* Set GME-M Mode Select bits back to NORMAL operation mode */ + printk(BIOS_DEBUG, " Normal operation mode\n"); + do_ram_command(RAM_COMMAND_NORMAL, 0); +/* delay(); + delay(); + delay(); + + print_debug("Ram enable 9\n"); + set_initialize_complete(); + + delay(); + delay(); + delay(); + delay(); + delay(); + + print_debug("After configuration:\n"); +*/ + /* dump_pci_devices(); */ + + /* + print_debug("\n\n***** RAM TEST *****\n"); + ram_check(0, 0xa0000); + ram_check(0x100000, 0x40000000); + */ +} + +//static void ram_read32(u8 dimm_start, u32 offset) +//{ + /* not implemented */ +//} + +//static void initialize_dimm_rows(void) +//{ + /* copied from i82830/raminit.c */ + /* not implemented */ +//} + +static void die_on_spd_error(int spd_return_value) +{ + if (spd_return_value < 0) + printk(BIOS_DEBUG, "Error reading SPD info: got %d\n", spd_return_value); +/* + if (spd_return_value < 0) + die("Error reading SPD info\n"); +*/ +} + +static struct dimm_size sdram_spd_get_page_size(u8 dimm_socket_address) +{ + uint16_t module_data_width; + int value; + struct dimm_size pgsz; + + pgsz.side1 = 0; + pgsz.side2 = 0; + + // Side 1 + value = spd_read_byte(dimm_socket_address, SPD_NUM_COLUMNS); + die_on_spd_error(value); + + pgsz.side1 = value & 0xf; // # columns in bank 1 + + /* Get the module data width and convert it to a power of two */ + value = spd_read_byte(dimm_socket_address, SPD_MODULE_DATA_WIDTH_MSB); + die_on_spd_error(value); + + module_data_width = (value & 0xff) << 8; + + value = spd_read_byte(dimm_socket_address, SPD_MODULE_DATA_WIDTH_LSB); + die_on_spd_error(value); + + module_data_width |= (value & 0xff); + + pgsz.side1 += log2(module_data_width); + + /* side two */ + value = spd_read_byte(dimm_socket_address, SPD_NUM_DIMM_BANKS); + die_on_spd_error(value); + + if (value > 2) + printk(BIOS_DEBUG, "Bad SPD value\n"); + + if (value == 2) { + pgsz.side2 = pgsz.side1; // Assume symmetric banks until we know differently + value = spd_read_byte(dimm_socket_address, SPD_NUM_COLUMNS); + die_on_spd_error(value); + + if ((value & 0xf0) != 0) { + // Asymmetric banks + pgsz.side2 -= value & 0xf; /* Subtract out columns on side 1 */ + pgsz.side2 += (value >> 4) & 0xf; /* Add in columns on side 2 */ + } + } + + return pgsz; +} + +/** + * Read the width in bits of each DIMM side's DRAMs via SPD (i.e. 4, 8, 16). + * + * @param dimm_socket_address SMBus address of DIMM socket to interrogate. + * @return Width in bits of each DIMM side's DRAMs. + */ +static struct dimm_size sdram_spd_get_width(u8 dimm_socket_address) +{ + int value; + struct dimm_size width; + + width.side1 = 0; + width.side2 = 0; + + value = spd_read_byte(dimm_socket_address, SPD_PRIMARY_SDRAM_WIDTH); + die_on_spd_error(value); + + width.side1 = value & 0x7f; // Mask off bank 2 flag + + if (value & 0x80) { + width.side2 = width.side1 << 1; // Bank 2 exists and is double-width + } else { + // If bank 2 exists, it's the same width as bank 1 + value = spd_read_byte(dimm_socket_address, SPD_NUM_DIMM_BANKS); + die_on_spd_error(value); + + switch (value) { + case 2: + width.side2 = width.side1; + break; + + default: + break; + } + } + + return width; +} + +/** + * Calculate the log base 2 size in bits of both DIMM sides. + * + * log2(# bits) = (# columns) + log2(data width) + + * (# rows) + log2(banks per SDRAM) + * + * Note that it might be easier to use SPD byte 31 here, it has the DIMM size + * as a multiple of 4MB. The way we do it now we can size both sides of an + * asymmetric DIMM. + * + * @param dimm SMBus address of DIMM socket to interrogate. + * @return log2(number of bits) for each side of the DIMM. + */ +static struct dimm_size spd_get_dimm_size(unsigned dimm) +{ + int value; + + // Start with log2(page size) + struct dimm_size sz = sdram_spd_get_page_size(dimm); + + if (sz.side1 > 0) { + value = spd_read_byte(dimm, SPD_NUM_ROWS); + die_on_spd_error(value); + + sz.side1 += value & 0xf; + + if (sz.side2 > 0) { + // Double-sided DIMM + if (value & 0xF0) + sz.side2 += value >> 4; // Asymmetric + else + sz.side2 += value; // Symmetric + } + + value = spd_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM); + die_on_spd_error(value); + + value = log2(value); + sz.side1 += value; + if (sz.side2 > 0) + sz.side2 += value; + } + + return sz; +} + +// static void set_dram_row_boundaries(void) { /* TODO */ } +// static void set_dram_row_attributes(void) { /* TODO */ } +// static void set_dram_timing(void) { /* TODO */ } +// static void sdram_set_registers(void) { /* TODO */ } + +static uint8_t spd_get_supported_dimms(void) +{ + int i; + uint8_t dimm_mask = 0; + +// for (i = 0; i < DIMM_SOCKETS; i++) { + for (i = 0; i < (2 * DIMM_SOCKETS); i++) { + u8 dimm = DIMM0 + i; + + struct dimm_size page_size; + struct dimm_size sdram_width; + + int spd_value; + + if (dimm == 0) + continue; + + if (spd_read_byte(dimm, SPD_MEMORY_TYPE) != SPD_MEMORY_TYPE_SDRAM_DDR) + // print a little warning, maybe? + continue; + + if ((spd_value = spd_read_byte(dimm, SPD_MODULE_VOLTAGE)) != SPD_VOLTAGE_SSTL2) { + printk(BIOS_DEBUG, "Skipping DIMM with unsupported voltage: %02x\n", spd_value); + continue; + } + + page_size = sdram_spd_get_page_size(dimm); + sdram_width = sdram_spd_get_width(dimm); + + // Validate DIMM page size + // The i855 only supports page sizes of 4, 8, 16 KB per channel + // NOTE: 4 KB = 32 Kb = 2^15 + // 16 KB = 128 Kb = 2^17 + + if ((page_size.side1 < 15) || (page_size.side1 > 17)) { + printk(BIOS_DEBUG, "Skipping DIMM with unsupported page size: %d\n", page_size.side1); + continue; + } + + // If DIMM is double-sided, verify side2 page size + if (page_size.side2 != 0) { + if ((page_size.side2 < 15) || (page_size.side2 > 17)) { + printk(BIOS_DEBUG, "Skipping DIMM with unsupported page size: %d\n", page_size.side2); + continue; + } + } + // Validate SDRAM width + // The i855 only supports x8 and x16 devices + if ((sdram_width.side1 != 8) && (sdram_width.side1 != 16)) { + printk(BIOS_DEBUG, "Skipping DIMM with unsupported width: %d\n", sdram_width.side2); + continue; + } + + // If DIMM is double-sided, verify side2 width + if (sdram_width.side2 != 0) { + if ((sdram_width.side2 != 8) + && (sdram_width.side2 != 16)) { + printk(BIOS_DEBUG, "Skipping DIMM with unsupported width: %d\n", sdram_width.side2); + continue; + } + } + // Made it through all the checks, this DIMM is usable + dimm_mask |= (1 << i); + } + + return dimm_mask; +} + +static void spd_set_row_attributes(uint8_t dimm_mask) +{ + int i; + uint16_t row_attributes = 0; + + for (i = 0; i < DIMM_SOCKETS; i++) { + u8 dimm = DIMM0 + i; + struct dimm_size page_size; + struct dimm_size sdram_width; + + if (!(dimm_mask & (1 << i))) { +// row_attributes |= 0x77 << (i << 3); + row_attributes |= 0x0 << (i << 3); // default value of DRA on i865 is 0x0 + continue; // This DIMM not usable + } + + // Get the relevant parameters via SPD + page_size = sdram_spd_get_page_size(dimm); + sdram_width = sdram_spd_get_width(dimm); + + // Update the DRAM Row Attributes. + // Page size is encoded as log2(page size in bits) - log2(2 KB) or 4 KB == 1, 8 KB == 3, 16KB == 3 +// i865: Page size is encoded as log2(page size in bits) - log2(2 KB) or 4 KB == 0, 8 KB == 1, 16KB == 2, 32KB == 3 + // NOTE: 2 KB = 16 Kb = 2^14 +// row_attributes |= (page_size.side1 - 14) << (i << 3); // Side 1 of each DIMM is an EVEN row + // i865: NOTE: 4 KB = 32 Kb = 2^15 + row_attributes |= (page_size.side1 - 15) << (i << 3); // Side 1 of each DIMM is an EVEN row + + if (sdram_width.side2 > 0) +// row_attributes |= (page_size.side2 - 14) << ((i << 3) + 4); // Side 2 is ODD + row_attributes |= (page_size.side2 - 15) << ((i << 3) + 4); // Side 2 is ODD +// else +// row_attributes |= 7 << ((i << 3) + 4); // "not populated", i865 doesn't have that bit + + /* on the asrock pi465gv (rev g/a 1.11), + physical ram slots "DDR2" and "DDR1" + are logically slots 2 and 1 (or 1 and 0) */ +// printk(BIOS_DEBUG, "DRA%d: 0x%x\n", i, row_attributes); +// printk(BIOS_DEBUG, "DRA: row %d,%d: 0x%x\n", i, i + 1, row_attributes); + printk(BIOS_DEBUG, "DRA: row %d,%d: 0x%x\n", i * 2, i * 2 + 1, row_attributes); + MCHBAR8(DRA + i) = row_attributes; + + /* go to the next DIMM */ + } + +// PRINTK_DEBUG("DRA: %04x\n", row_attributes); + + /* Write the new row attributes register */ +// pci_write_config16(NORTHBRIDGE_MMC, DRA, row_attributes); +} + +static void spd_set_dram_controller_mode(uint8_t dimm_mask) +{ + int i; + + // Initial settings +// u32 controller_mode = pci_read_config32(NORTHBRIDGE_MMC, DRC); + u32 controller_mode = MCHBAR32(DRC); +// u32 system_refresh_mode = (controller_mode >> 7) & 7; + u32 system_refresh_mode = (controller_mode >> 8) & 7; // i865: RMS is at bits 10:8 + +// controller_mode |= (1 << 20); // ECC +// controller_mode |= (1 << 15); // RAS lockout +// controller_mode |= (1 << 12); // Address Tri-state enable (ADRTRIEN), FIXME: how is this detected????? +// controller_mode |= (2 << 10); // FIXME: Undocumented, really needed????? + +// for (i = 0; i < DIMM_SOCKETS; i++) { + for (i = 0; i < (2 * DIMM_SOCKETS); i++) { + u8 dimm = DIMM0 + i; + uint32_t dimm_refresh_mode; + int value; +// u8 tRCD, tRP; + + if (!(dimm_mask & (1 << i))) { + continue; // This DIMM not usable + } + + // Disable ECC mode if any one of the DIMMs does not support ECC +// no ECC on i865, disabling +// value = spd_read_byte(dimm, SPD_DIMM_CONFIG_TYPE); +// die_on_spd_error(value); +// if (value != ERROR_SCHEME_ECC) +// controller_mode &= ~(3 << 20); + + value = spd_read_byte(dimm, SPD_REFRESH); + die_on_spd_error(value); + value &= 0x7f; // Mask off self-refresh bit + if (value > MAX_SPD_REFRESH_RATE) { + print_err("unsupported refresh rate\n"); + continue; + } + // Get the appropriate i855 refresh mode for this DIMM + dimm_refresh_mode = refresh_rate_map[value]; + if (dimm_refresh_mode > 7) { + print_err("unsupported refresh rate\n"); + continue; + } + // If this DIMM requires more frequent refresh than others, + // update the system setting + if (refresh_frequency[dimm_refresh_mode] > + refresh_frequency[system_refresh_mode]) + system_refresh_mode = dimm_refresh_mode; + + /* FIXME: is this correct? */ +// tRCD = spd_read_byte(dimm, SPD_tRCD); +// tRP = spd_read_byte(dimm, SPD_tRP); +// no RAS lockout on i865 +// if (tRCD != tRP) { +// PRINTK_DEBUG(" Disabling RAS lockouk due to tRCD (%d) != tRP (%d)\n", tRCD, tRP); +// printk(BIOS_DEBUG, " Disabling RAS lockouk due to tRCD (%d) != tRP (%d)\n", tRCD, tRP); +// controller_mode &= ~(1 << 15); +// } + + /* go to the next DIMM */ + } + +// controller_mode &= ~(7 << 7); +// controller_mode |= (system_refresh_mode << 7); + controller_mode &= ~(7 << 8); + controller_mode |= (system_refresh_mode << 8); +// PRINTK_DEBUG("DRC: %08x\n", controller_mode); + printk(BIOS_DEBUG, "DRC: %08x\n", controller_mode); + +// pci_write_config32(NORTHBRIDGE_MMC, DRC, controller_mode); + MCHBAR32(DRC) = controller_mode; +} + +static void spd_set_dram_timing(uint8_t dimm_mask) +{ + int i; + u32 dram_timing; + + // CAS# latency bitmasks in SPD_ACCEPTABLE_CAS_LATENCIES format + // NOTE: i82822 supports only 2.0 and 2.5 +// uint32_t system_compatible_cas_latencies = SPD_CAS_LATENCY_2_0 | SPD_CAS_LATENCY_2_5; + +/* SPD_CAS_LATENCY_2_0 | SPD_CAS_LATENCY_2_5 | SPD_CAS_LATENCY_3_0 == 0x1c */ + uint32_t system_compatible_cas_latencies = SPD_CAS_LATENCY_2_0 | SPD_CAS_LATENCY_2_5 | SPD_CAS_LATENCY_3_0; +// uint32_t system_compatible_cas_latencies = DRT_CAS_2_0 | DRT_CAS_2_5 | DRT_CAS_3_0; + uint8_t slowest_row_precharge = 0; + uint8_t slowest_ras_cas_delay = 0; + uint8_t slowest_active_to_precharge_delay = 0; + +// for (i = 0; i < DIMM_SOCKETS; i++) { + for (i = 0; i < (2 * DIMM_SOCKETS); i++) { + u8 dimm = DIMM0 + i; + int value; + uint32_t current_cas_latency; + uint32_t dimm_compatible_cas_latencies; + if (!(dimm_mask & (1 << i))) + continue; // This DIMM not usable + + value = spd_read_byte(dimm, SPD_ACCEPTABLE_CAS_LATENCIES); + printk(BIOS_DEBUG, "SPD_ACCEPTABLE_CAS_LATENCIES: %d\n", value); + die_on_spd_error(value); + + dimm_compatible_cas_latencies = value & 0x7f; // Start with all supported by DIMM + printk(BIOS_DEBUG, "dimm_compatible_cas_latencies #1: %d\n", dimm_compatible_cas_latencies); + + current_cas_latency = 1 << log2(dimm_compatible_cas_latencies); // Max supported by DIMM + printk(BIOS_DEBUG, "current_cas_latency: %d\n", current_cas_latency); + + // Can we support the highest CAS# latency? + value = spd_read_byte(dimm, SPD_MIN_CYCLE_TIME_AT_CAS_MAX); + die_on_spd_error(value); + printk(BIOS_DEBUG, "SPD_MIN_CYCLE_TIME_AT_CAS_MAX: %d.%d\n", value >> 4, value & 0xf); + + // NOTE: At 133 MHz, 1 clock == 7.52 ns + if (value > 0x75) { + // Our bus is too fast for this CAS# latency + // Remove it from the bitmask of those supported by the DIMM that are compatible + dimm_compatible_cas_latencies &= ~current_cas_latency; + printk(BIOS_DEBUG, "dimm_compatible_cas_latencies #2: %d\n", dimm_compatible_cas_latencies); + } + // Can we support the next-highest CAS# latency (max - 0.5)? + + current_cas_latency >>= 1; + if (current_cas_latency != 0) { + value = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_2ND); + die_on_spd_error(value); + printk(BIOS_DEBUG, "SPD_SDRAM_CYCLE_TIME_2ND: %d.%d\n", value >> 4, value & 0xf); + if (value > 0x75) { + dimm_compatible_cas_latencies &= ~current_cas_latency; + printk(BIOS_DEBUG, "dimm_compatible_cas_latencies #2: %d\n", dimm_compatible_cas_latencies); + } + } + // Can we support the next-highest CAS# latency (max - 1.0)? + current_cas_latency >>= 1; + if (current_cas_latency != 0) { + value = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_3RD); + printk(BIOS_DEBUG, "SPD_SDRAM_CYCLE_TIME_3RD: %d.%d\n", value >> 4, value & 0xf); + die_on_spd_error(value); + if (value > 0x75) { + dimm_compatible_cas_latencies &= ~current_cas_latency; + printk(BIOS_DEBUG, "dimm_compatible_cas_latencies #2: %d\n", dimm_compatible_cas_latencies); + } + } + // Restrict the system to CAS# latencies compatible with this DIMM + system_compatible_cas_latencies &= dimm_compatible_cas_latencies; + + value = spd_read_byte(dimm, SPD_MIN_ROW_PRECHARGE_TIME); + die_on_spd_error(value); + if (value > slowest_row_precharge) + slowest_row_precharge = value; + + value = spd_read_byte(dimm, SPD_MIN_RAS_TO_CAS_DELAY); + die_on_spd_error(value); + if (value > slowest_ras_cas_delay) + slowest_ras_cas_delay = value; + + value = spd_read_byte(dimm, SPD_MIN_ACTIVE_TO_PRECHARGE_DELAY); + die_on_spd_error(value); + if (value > slowest_active_to_precharge_delay) + slowest_active_to_precharge_delay = value; + + /* go to the next DIMM */ + } + printk(BIOS_DEBUG, "CAS latency: %d\n", system_compatible_cas_latencies); + +// dram_timing = pci_read_config32(NORTHBRIDGE_MMC, DRT); + dram_timing = MCHBAR32(DRT); +// dram_timing &= ~(DRT_CAS_MASK | DRT_TRP_MASK | DRT_RCD_MASK); + dram_timing &= ~(DRT_CAS_MASK | DRT_TRP_MASK | DRT_TRCD_MASK); + printk(BIOS_DEBUG, "DRT: %08x\n", dram_timing); + + if (system_compatible_cas_latencies & SPD_CAS_LATENCY_2_0) { + dram_timing |= DRT_CAS_2_0; + } else if (system_compatible_cas_latencies & SPD_CAS_LATENCY_2_5) { + dram_timing |= DRT_CAS_2_5; + } else if (system_compatible_cas_latencies & SPD_CAS_LATENCY_3_0) { + dram_timing |= DRT_CAS_3_0; + } else + die("No CAS# latencies compatible with all DIMMs!!\n"); + +// uint32_t current_cas_latency = dram_timing & DRT_CAS_MASK; + + /* tRP */ + + printk(BIOS_DEBUG, "slowest_row_precharge: %d.%d\n", slowest_row_precharge >> 2, slowest_row_precharge & 0x3); + // i855 supports only 2, 3 or 4 clocks for tRP + if (slowest_row_precharge > (30 << 2)) // 30 = 11110b = tRCD = 2 dram clocks, tCL = reserved + die("unsupported DIMM tRP"); // > 30.0 ns: 5 or more clocks + else if (slowest_row_precharge > ( (22 << 2) | (2 << 0) )) + // 22 = 10110b = tRCD = 2 dram clocks, tCL = 2 + // 2 = 10b = 2 dram clocks (tRP) + dram_timing |= DRT_TRP_4; // > 22.5 ns: 4 or more clocks + else if (slowest_row_precharge > (15 << 2)) // 15 = 1111b = tRCD = reserved, tCL = 2 + dram_timing |= DRT_TRP_3; // > 15.0 ns: 3 clocks + else + dram_timing |= DRT_TRP_2; // <= 15.0 ns: 2 clocks + + /* tRCD */ + + printk(BIOS_DEBUG, "slowest_ras_cas_delay: %d.%d\n", slowest_ras_cas_delay >> 2, slowest_ras_cas_delay & 0x3); + // i855 supports only 2, 3 or 4 clocks for tRCD + if (slowest_ras_cas_delay > ((30 << 2))) + die("unsupported DIMM tRCD"); // > 30.0 ns: 5 or more clocks + else if (slowest_ras_cas_delay > ((22 << 2) | (2 << 0))) +// dram_timing |= DRT_RCD_4; // > 22.5 ns: 4 or more clocks + dram_timing |= DRT_TRCD_4; // > 22.5 ns: 4 or more clocks + else if (slowest_ras_cas_delay > (15 << 2)) +// dram_timing |= DRT_RCD_3; // > 15.0 ns: 3 clocks + dram_timing |= DRT_TRCD_3; // > 15.0 ns: 3 clocks + else +// dram_timing |= DRT_RCD_2; // <= 15.0 ns: 2 clocks + dram_timing |= DRT_TRCD_2; // <= 15.0 ns: 2 clocks + + /* tRAS, min */ + + printk(BIOS_DEBUG, "slowest_active_to_precharge_delay: %d\n", slowest_active_to_precharge_delay); + // i855 supports only 5, 6, 7 or 8 clocks for tRAS + // 5 clocks ~= 37.6 ns, 6 clocks ~= 45.1 ns, 7 clocks ~= 52.6 ns, 8 clocks ~= 60.1 ns + // TODO + if (slowest_active_to_precharge_delay > 60) + die("unsupported DIMM tRAS"); // > 52 ns: 8 or more clocks + else if (slowest_active_to_precharge_delay > 52) + dram_timing |= DRT_TRAS_MIN_8; // 46-52 ns: 7 clocks + else if (slowest_active_to_precharge_delay > 45) + dram_timing |= DRT_TRAS_MIN_7; // 46-52 ns: 7 clocks + else if (slowest_active_to_precharge_delay > 37) + dram_timing |= DRT_TRAS_MIN_6; // 38-45 ns: 6 clocks + else + dram_timing |= DRT_TRAS_MIN_5; // < 38 ns: 5 clocks + + /* FIXME: guess work starts here... + * + * Intel refers to DQ turn-arround values for back to calculate the values, + * but i have no idea what this means + */ + + /* + * Back to Back Read-Write command spacing (DDR, different Rows/Bank) + */ + /* Set to a 3 clock back to back read to write turn around. + * 2 is a good delay if the CAS latency is 2.0 */ +// dram_timing &= ~(3 << 28); +// if (current_cas_latency == DRT_CAS_2_0) +// dram_timing |= (2 << 28); // 2 clocks +// else +// dram_timing |= (1 << 28); // 3 clocks + + /* + * Back to Back Read-Write command spacing (DDR, same or different Rows/Bank) + */ +// dram_timing &= ~(3 << 26); +// if (current_cas_latency == DRT_CAS_2_0) +// dram_timing |= (2 << 26); // 5 clocks +// else +// dram_timing |= (1 << 26); // 6 clocks + + /* + * Back To Back Read-Read commands spacing (DDR, different Rows): + */ +// dram_timing &= ~(1 << 25); +// dram_timing |= (1 << 25); // 3 clocks + + printk(BIOS_DEBUG, "DRT: %08x\n", dram_timing); +// pci_write_config32(NORTHBRIDGE_MMC, DRT, dram_timing); + MCHBAR32(DRT) = dram_timing; +} + +static void spd_set_dram_size(uint8_t dimm_mask) +{ + int i; + int total_dram = 0; + uint32_t drb_reg = 0; + +// for (i = 0; i < DIMM_SOCKETS; i++) { + for (i = 0; i < (2 * DIMM_SOCKETS); i++) { + u8 dimm = DIMM0 + i; + struct dimm_size sz; + + if (!(dimm_mask & (1 << i))) { + /* fill values even for not present DIMMs */ +// drb_reg |= (total_dram << (i * 16)); +// drb_reg |= (total_dram << ((i * 16) + 8)); + drb_reg |= (total_dram << (i * 32)); + drb_reg |= (total_dram << ((i * 32) + 8)); + + continue; // This DIMM not usable + } + sz = spd_get_dimm_size(dimm); + +// total_dram += (1 << (sz.side1 - 28)); +// drb_reg |= (total_dram << (i * 16)); + total_dram += (1 << (sz.side1 - 30)); + drb_reg |= (total_dram << (i * 32)); + +// total_dram += (1 << (sz.side2 - 28)); +// drb_reg |= (total_dram << ((i * 16) + 8)); + total_dram += (1 << (sz.side2 - 30)); + drb_reg |= (total_dram << ((i * 32) + 8)); + + printk(BIOS_DEBUG, "DRB: %08x\n", drb_reg); + MCHBAR8(DRB + i) = drb_reg; + } +// printk(BIOS_DEBUG, "DRB: %08x\n", drb_reg); +// pci_write_config32(NORTHBRIDGE_MMC, DRB, drb_reg); +} + +static void enable_refresh(void) +{ + printk(BIOS_DEBUG, "Enabling refresh (RAM_COMMAND_REFRESH)\n"); + MCHBAR32(DRC) |= RAM_COMMAND_REFRESH << 8; +} + +/* from src/northbridge/intel/i945/raminit.c and util/inteltool/memory.c */ +static void sdram_dump_mchbar_registers(void) +{ + int i; + + printk(BIOS_DEBUG, "Dumping MCHBAR registers:\n"); + for (i = 0; i < 0xffff; i += 4) { + if ( (MCHBAR32(i) == 0) || (MCHBAR32(i) == 0xffffffff) ) + continue; + switch (i) { + case (DRB + 0): + printk(BIOS_DEBUG, " DRB0: 0x%x\n", MCHBAR32(i)); + case (DRB + 1): + printk(BIOS_DEBUG, " DRB1: 0x%x\n", MCHBAR32(i)); + case (DRB + 2): + printk(BIOS_DEBUG, " DRB2: 0x%x\n", MCHBAR32(i)); + case (DRB + 3): + printk(BIOS_DEBUG, " DRB3: 0x%x\n", MCHBAR32(i)); + case (DRB + 4): + printk(BIOS_DEBUG, " DRB4: 0x%x\n", MCHBAR32(i)); + case (DRB + 5): + printk(BIOS_DEBUG, " DRB5: 0x%x\n", MCHBAR32(i)); + case (DRB + 6): + printk(BIOS_DEBUG, " DRB6: 0x%x\n", MCHBAR32(i)); + case (DRB + 7): + printk(BIOS_DEBUG, " DRB7: 0x%x\n", MCHBAR32(i)); + + case (DRA + 0): + printk(BIOS_DEBUG, " DRA0: 0x%x\n", MCHBAR32(i)); + case (DRA + 1): + printk(BIOS_DEBUG, " DRA1: 0x%x\n", MCHBAR32(i)); + case (DRA + 2): + printk(BIOS_DEBUG, " DRA2: 0x%x\n", MCHBAR32(i)); + case (DRA + 3): + printk(BIOS_DEBUG, " DRA3: 0x%x\n", MCHBAR32(i)); + case (DRA + 4): + printk(BIOS_DEBUG, " DRA4: 0x%x\n", MCHBAR32(i)); + case (DRA + 5): + printk(BIOS_DEBUG, " DRA5: 0x%x\n", MCHBAR32(i)); + case (DRA + 6): + printk(BIOS_DEBUG, " DRA6: 0x%x\n", MCHBAR32(i)); + case (DRA + 7): + printk(BIOS_DEBUG, " DRA7: 0x%x\n", MCHBAR32(i)); + + case DRT: + printk(BIOS_DEBUG, " DRT: 0x%x\n", MCHBAR32(i)); + case DRC: + printk(BIOS_DEBUG, " DRC: 0x%x\n", MCHBAR32(i)); + default: + printk(BIOS_DEBUG, "0x%x: 0x%x\n", i, MCHBAR32(i)); + } + } +} + +static void early_northbridge_set_registers(void) +{ + u8 reg8; + + /* Undocumented register */ + reg8 = pci_read_config8(NORTHBRIDGE, 0xf4); + + /* + Writing 0x2 to northbridge register 0xf4 + exposes the PCI registers of device 6. + */ + //reg8 |= 0x2; /* guesswork: the default value is 0x0 */ + reg8 = 0x2; + + printk(BIOS_DEBUG, "Enabling access to (the registers of) device 6\n"); + pci_write_config8(NORTHBRIDGE, 0xf4, reg8); + + printk(BIOS_DEBUG, "Configuring BAR6 as 0x%x\n", DEFAULT_MCHBAR); + pci_write_config32(NORTHBRIDGE_MMC, BAR6, DEFAULT_MCHBAR); + + printk(BIOS_DEBUG, "Enabling Memory Access Enable (MAE) in PCICMD6\n"); + pci_write_config16(NORTHBRIDGE_MMC, PCICMD6, 0x2); +} + +static void northbridge_set_pam(void) +{ + printk(BIOS_DEBUG, "Configuring PAM0..PAM6\n"); + pci_write_config8(NORTHBRIDGE, PAM0, 0x10); + pci_write_config8(NORTHBRIDGE, PAM1, 0x11); + pci_write_config8(NORTHBRIDGE, PAM2, 0x1); + pci_write_config8(NORTHBRIDGE, PAM3, 0x0); + pci_write_config8(NORTHBRIDGE, PAM4, 0x0); + pci_write_config8(NORTHBRIDGE, PAM5, 0x33); + pci_write_config8(NORTHBRIDGE, PAM6, 0x33); +} + +static void northbridge_set_registers(void) +{ + printk(BIOS_DEBUG, "Configuring APBASE\n"); + pci_write_config32(NORTHBRIDGE, APBASE, 0xfe800008); + + printk(BIOS_DEBUG, "Configuring APSIZE\n"); + pci_write_config8(NORTHBRIDGE, APSIZE, 0x3f); + + printk(BIOS_DEBUG, "Configuring GC\n"); /* IVD=0, IGDIS=0, GMS=8 megabyte */ + pci_write_config8(NORTHBRIDGE, GC, 0x34); + + printk(BIOS_DEBUG, "Configuring AMTT\n"); + pci_write_config8(NORTHBRIDGE, AMTT, 0x20); + + printk(BIOS_DEBUG, "Configuring LPTT\n"); + pci_write_config8(NORTHBRIDGE, LPTT, 0x10); + + printk(BIOS_DEBUG, "Configuring GMCHCFG\n"); + pci_write_config16(NORTHBRIDGE, GMCHCFG, 0x40d); + + printk(BIOS_DEBUG, "Configuring TOUD\n"); + pci_write_config16(NORTHBRIDGE, TOUD, 0x1f80); + + printk(BIOS_DEBUG, "Configuring PCISTS\n"); + pci_write_config16(NORTHBRIDGE, PCISTS, 0x2009); + + printk(BIOS_DEBUG, "Writing SVID and SID\n"); + pci_write_config16(NORTHBRIDGE, SVID, 0x1849); + pci_write_config16(NORTHBRIDGE, SID, 0x2570); + + printk(BIOS_DEBUG, "Configuring ERRSTS\n"); + pci_write_config16(NORTHBRIDGE, ERRSTS, 0x100); +} + +static void northbridge_set_undocumented_registers(void) +{ + u8 reg8; + + printk(BIOS_DEBUG, "Configuring undocumented register 0x54\n"); + /* + guesswork, the default value is 0x18 and 0x1c is the value from lspci -nnvvvxxx. + conclusion: add 0x4 */ + reg8 = pci_read_config8(NORTHBRIDGE, 0x54); + reg8 |= 0x4; + pci_write_config8(NORTHBRIDGE, 0x54, reg8); + + printk(BIOS_DEBUG, "Configuring undocumented register 0x9d\n"); + reg8 = pci_read_config8(NORTHBRIDGE, 0xc9d); + reg8 |= 0x8; + pci_write_config8(NORTHBRIDGE, 0x9d, reg8); +} + +//static void hardcoded_initialization(void) +//{ + // int i; + +// printk(BIOS_DEBUG, "Configuring DRT\n"); +// MCHBAR32(DRT) = 0x56e40d00; /* single-channel, 512MB in the first (physical) slot */ +// printk(BIOS_DEBUG, " DRT after configuring (should be 0x56e40d00): 0x%x\n", MCHBAR32(DRT)); + +// printk(BIOS_DEBUG, "Configuring DRB0..DRB7\n"); + + /* single-channel, 512MB in the first (physical) slot */ +// MCHBAR8(DRB + 0) = 0x4; +// MCHBAR8(DRB + 1) = 0x8; +// MCHBAR8(DRB + 2) = 0x8; +// MCHBAR8(DRB + 3) = 0x8; +// MCHBAR8(DRB + 4) = 0x8; +// MCHBAR8(DRB + 5) = 0x8; +// MCHBAR8(DRB + 6) = 0x8; +// MCHBAR8(DRB + 7) = 0x8; + // for (i = 0; i < 8; i++) { + // printk(BIOS_DEBUG, " DRB%i after configuring (should be 0x4 for DRB0, 0x8 for DRB1-7): 0x%x\n", i, MCHBAR8(DRB + i)); + // } + +// printk(BIOS_DEBUG, "Configuring DRA0..DRA7\n"); + + /* single-channel, 512MB in the first (physical) slot */ +// MCHBAR8(DRA + 0) = 0x0; +// MCHBAR8(DRA + 1) = 0x11; // 8 kilobyte on each row +// MCHBAR8(DRA + 2) = 0x0; +// MCHBAR8(DRA + 3) = 0x0; + // for (i = 0; i < 8; i++) { + // printk(BIOS_DEBUG, " DRA%i after configuring (should be 0x0 for DRA0, DRA2 and DRA3, 0x11 for DRA1: 0x%x\n", + // i, MCHBAR8(DRA + i)); + // } + + // BAR6_32(DRC) = 0x20104271; + + // printk(BIOS_DEBUG, "All aboard the undocumented registers train :(\n"); + +/* + MCHBAR32(0x6c) = 0xa801; + MCHBAR32(0xb0) = 0x40830; + MCHBAR32(0x100) = 0x89b; + MCHBAR32(0x104) = 0x4ad; + MCHBAR32(0x130) = 0x88d; + MCHBAR32(0x138) = 0x210843c; + MCHBAR32(0x140) = 0x1721c; + MCHBAR32(0x144) = 0xe380fff; + MCHBAR32(0x170) = 0x1a00018b; + MCHBAR32(0x1a0) = 0x3d0524fd; + MCHBAR32(0x200) = 0x1; + MCHBAR32(0x208) = 0x3937; + MCHBAR32(0x300) = 0x32; + MCHBAR32(0x800) = 0xdddddddd; +*/ + // sdram_dump_mchbar_registers(); // from i945 +//} + +static void sdram_initialize(void) +//void sdram_initialize(void) +{ + /* First things first. */ + early_northbridge_set_registers(); + + uint8_t dimm_mask; + + printk(BIOS_DEBUG, "Reading SPD data...\n"); + dimm_mask = spd_get_supported_dimms(); + + if (dimm_mask == 0) { + printk(BIOS_DEBUG, "No usable memory for this controller\n"); + } + else { + printk(BIOS_DEBUG, "DIMM mask: 0x%x\n", dimm_mask); + + spd_set_row_attributes(dimm_mask); // done? + spd_set_dram_controller_mode(dimm_mask); // TODO + spd_set_dram_timing(dimm_mask); // TODO: tRAS + spd_set_dram_size(dimm_mask); // TODO + } + + sdram_enable(); + + enable_refresh(); + + set_initialization_complete(); + + /* Setup Initial Northbridge Registers */ + northbridge_set_pam(); + northbridge_set_registers(); + northbridge_set_undocumented_registers(); + + sdram_dump_mchbar_registers(); + + printk(BIOS_DEBUG, "Northbridge following SDRAM init:\n"); + + dump_pci_device(NORTHBRIDGE); + dump_pci_device(NORTHBRIDGE_MMC); +// dump_pci_device(PCI_DEV(0, 0x1e, 0)); +// dump_pci_device(PCI_DEV(0, 0x1f, 0)); +// dump_pci_device(PCI_DEV(0, 0x1f, 3)); +} diff --git a/src/northbridge/intel/i865/raminit.h b/src/northbridge/intel/i865/raminit.h new file mode 100644 index 0000000..bf47053 --- /dev/null +++ b/src/northbridge/intel/i865/raminit.h @@ -0,0 +1,181 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2006 Jon Dufresne jon.dufresne@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 + */ + +// #ifndef NORTHBRIDGE_INTEL_I865_RAMINIT_H +// #define NORTHBRIDGE_INTEL_I865_RAMINIT_H +#ifndef RAMINIT_H +#define RAMINIT_H + +#define DIMM_SOCKETS 4 + +/* i865 Northbridge PCI devices */ +#define NORTHBRIDGE PCI_DEV(0, 0, 0) +#define NORTHBRIDGE_MMC PCI_DEV(0, 6, 0) // Overflow device + +/*----------------------------------------------------------------------------- +Macros and definitions: +-----------------------------------------------------------------------------*/ +//#define VALIDATE_DIMM_COMPATIBILITY + +#define delay() udelay(200) + +/* should dispose of this. */ +// burst length can be 4 or 8 in single-channel or 8 in dual-channel +// interleaved bursts versus sequential bursts.. no idea about the capabilities of i865, so I left it out +//#define VG86X_MODE (SDRAM_BURST_4 | SDRAM_BURST_INTERLEAVED | SDRAM_CAS_2_5) +//#define VG86X_MODE (SDRAM_BURST_4 | SDRAM_CAS_3) // SDRAM_CAS_* == tCL? +#define VG85X_MODE (SDRAM_BURST_4 | SDRAM_BURST_INTERLEAVED | SDRAM_CAS_2_5) + +/* Main Memory Control */ +#define DEFAULT_MCHBAR 0xfecf0000 /* ? KB */ + +#define MCHBAR8(x) *((volatile u8 *)(DEFAULT_MCHBAR + x)) +//#define MCHBAR16(x) *((volatile u16 *)(DEFAULT_MCHBAR + x)) // unused +#define MCHBAR32(x) *((volatile u32 *)(DEFAULT_MCHBAR + x)) + +/* Memory mapped registers */ +#define DRB 0x0 /* DRAM Row 0-7 Boundary */ +#define DRA 0x10 /* DRAM Row 0-7 Attribute */ +#define DRT 0x60 /* DRAM Timing */ +#define DRC 0x68 /* DRAM Controller Mode */ + +/* Northbridge (device 0) */ +#define PAM0 0x90 /* Programmable Attribute Map #0 */ +#define PAM1 0x91 /* Programmable Attribute Map #1 */ +#define PAM2 0x92 /* Programmable Attribute Map #2 */ +#define PAM3 0x93 /* Programmable Attribute Map #3 */ +#define PAM4 0x94 /* Programmable Attribute Map #4 */ +#define PAM5 0x95 /* Programmable Attribute Map #5 */ +#define PAM6 0x96 /* Programmable Attribute Map #6 */ + +/* DRC[29] - Initialization Complete (IC) */ +//#define RAM_COMMAND_IC 0x1 +//#define DRC_DONE (RAM_COMMAND_IC << 29) +#define RAM_INITIALIZATION_COMPLETE (1 << 29) + +/* DRC[22:21] - Number of Channels (CHAN) */ +// TODO: rename to DRC_*_CHANNEL_* ? +#define RAM_SINGLE_CHANNEL 0x0 +#define RAM_DUAL_CHANNEL_LINEAR 0x1 +#define RAM_DUAL_CHANNEL_TILEAR 0x2 + +/* DRC[10:8] - Refresh Mode Select (RMS) + * 0x1 for Refresh interval 15.6 us + * 0x2 for Refresh interval 7.8 us + * 0x3 for Refresh interval 64 usec + * 0x7 for Refresh interval 64 Clocks. (Fast Refresh Mode) + */ +// TODO: rename to DRC_RMS_* ? +// #define RAM_RMS_15_6 0x1 /* usec */ +// #define RAM_RMS_7_8 0x2 /* usec */ +// #define RAM_RMS_64 0x3 /* usec */ +// #define RAM_RMS_FAST 0x7 /* clocks */ +#define RAM_COMMAND_REFRESH 0x1 + +/* DRC[6:4] - Mode Select (SMS) */ +// TODO: mask? +// TODO: rename to DRC_SMS_* ? +#define RAM_COMMAND_POST_RESET 0x0 +#define RAM_COMMAND_NOP 0x1 +#define RAM_COMMAND_PRECHARGE 0x2 +#define RAM_COMMAND_MRS 0x3 +#define RAM_COMMAND_EMRS 0x4 +#define RAM_COMMAND_CBR 0x6 +#define RAM_COMMAND_NORMAL 0x7 + +/* Activate to Precharge delay (tRAS) */ +#define DRT_TRAS_MAX_70 (1 << 10) +#define DRT_TRAS_MAX_120 (0 << 10) +#define DRT_TRAS_MIN_MASK (5 << 7) // conflicts with DRT_TRAS_MIN_5 +#define DRT_TRAS_MIN_10 (0 << 7) +#define DRT_TRAS_MIN_9 (1 << 7) +#define DRT_TRAS_MIN_8 (2 << 7) +#define DRT_TRAS_MIN_7 (3 << 7) +#define DRT_TRAS_MIN_6 (4 << 7) +#define DRT_TRAS_MIN_5 (5 << 7) + +/* CAS# latency (tCL) */ +#define DRT_TCL_MASK (3 << 5) +#define DRT_TCL_2_0 (1 << 5) +#define DRT_TCL_2_5 (0 << 5) +#define DRT_TCL_3_0 (2 << 5) + +/* DRAM RAS# to CAS delay (tRCD) */ +#define DRT_TRCD_MASK (3 << 2) +#define DRT_TRCD_4 (0 << 2) +#define DRT_TRCD_3 (1 << 2) +#define DRT_TRCD_2 (2 << 2) + +/* DRAM RAS# precharge (tRP) */ +#define DRT_TRP_MASK 3 +#define DRT_TRP_4 0 +#define DRT_TRP_3 1 +#define DRT_TRP_2 2 + +// moved from i855.h +#define DRT_CAS_MASK (3 << 5) +#define DRT_CAS_2_0 (1 << 5) +#define DRT_CAS_2_5 (0 << 5) +#define DRT_CAS_3_0 (2 << 5) + +struct sys_info { // copied from i945, not yet used + u16 memory_frequency; /* 400, 533 or 667 */ + u16 fsb_frequency; /* 400, 533 or 667 */ + + u8 trp; /* calculated by sdram_detect_smallest_tRP() */ + u8 trcd; /* calculated by sdram_detect_smallest_tRCD() */ + u8 tras; /* calculated by sdram_detect_smallest_tRAS() */ + // u8 trfc; /* calculated by sdram_detect_smallest_tRFC() */ + // u8 twr; /* calculated by sdram_detect_smallest_tWR() */ + + u8 cas; /* 3, 4 or 5 */ + u8 refresh; /* 0 = 15.6us, 1 = 7.8us */ + + u8 dual_channel; /* 0 or 1 */ + u8 interleaved; + + // u8 mvco4x; /* 0 (8x) or 1 (4x) */ + // u8 clkcfg_bit7; + // u8 boot_path; +// #define BOOT_PATH_NORMAL 0 +// #define BOOT_PATH_RESET 1 +// #define BOOT_PATH_RESUME 2 + + // u8 package; /* 0 = planar, 1 = stacked */ +// #define SYSINFO_PACKAGE_PLANAR 0x00 +// #define SYSINFO_PACKAGE_STACKED 0x01 + u8 dimm[2 * DIMM_SOCKETS]; +#define SYSINFO_DIMM_X16DS 0x00 +#define SYSINFO_DIMM_X8DS 0x01 +#define SYSINFO_DIMM_X16SS 0x02 +#define SYSINFO_DIMM_X8DDS 0x03 +#define SYSINFO_DIMM_NOT_POPULATED 0x04 + + u8 banks[2 * DIMM_SOCKETS]; + + u8 banksize[2 * 2 * DIMM_SOCKETS]; + const u8 *spd_addresses; + +} __attribute__ ((packed)); + + +//void sdram_initialize(void); + +#endif /* NORTHBRIDGE_INTEL_I865_RAMINIT_H */ diff --git a/src/northbridge/intel/i865/reset_test.c b/src/northbridge/intel/i865/reset_test.c new file mode 100644 index 0000000..c465c53 --- /dev/null +++ b/src/northbridge/intel/i865/reset_test.c @@ -0,0 +1,38 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2006 Jon Dufresne jon.dufresne@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 + */ + +#include "raminit.h" + + /* If I have already booted once skip a bunch of initialization */ + /* To see if I have already booted I check to see if memory + * has been enabled. + */ +static int bios_reset_detected(void) +{ + uint32_t dword; + + dword = BAR6_32(DRC); + + if( (dword & DRC_DONE) != 0 ) { + return 1; + } + + return 0; +} diff --git a/src/southbridge/intel/i82801ex/early_smbus.c b/src/southbridge/intel/i82801ex/early_smbus.c index cdf1f62..1c67c51 100644 --- a/src/southbridge/intel/i82801ex/early_smbus.c +++ b/src/southbridge/intel/i82801ex/early_smbus.c @@ -1,6 +1,6 @@ #include "smbus.h"
-#define SMBUS_IO_BASE 0x0f00 +//#define SMBUS_IO_BASE 0x0f00
static void enable_smbus(void) { @@ -9,7 +9,7 @@ static void enable_smbus(void) print_spew("SMBus controller enabled\n");
pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1); - print_debug_hex32(pci_read_config32(dev, 0x20)); + printk(BIOS_DEBUG, "SMB_BASE = 0x%x\n", pci_read_config32(dev, SMB_BASE)); /* Set smbus enable */ pci_write_config8(dev, 0x40, 1); /* Set smbus iospace enable */ diff --git a/src/southbridge/intel/i82801ex/smbus.h b/src/southbridge/intel/i82801ex/smbus.h index f330c0a..0fa6b84 100644 --- a/src/southbridge/intel/i82801ex/smbus.h +++ b/src/southbridge/intel/i82801ex/smbus.h @@ -1,5 +1,8 @@ #include <device/smbus_def.h>
+#define SMBUS_IO_BASE 0x400 +#define SMB_BASE 0x20 + #define SMBHSTSTAT 0x0 #define SMBHSTCTL 0x2 #define SMBHSTCMD 0x3 diff --git a/src/superio/winbond/w83627thg/early_serial.c b/src/superio/winbond/w83627thg/early_serial.c index 559e982..a54139f 100644 --- a/src/superio/winbond/w83627thg/early_serial.c +++ b/src/superio/winbond/w83627thg/early_serial.c @@ -45,3 +45,14 @@ static void inline w83627thg_enable_serial(device_t dev, u16 iobase) pnp_set_enable(dev, 1); pnp_exit_ext_func_mode(dev); } + +static void w83627thg_set_clksel_48(device_t dev) +{ + u8 reg8; + + pnp_enter_ext_func_mode(dev); + reg8 = pnp_read_config(dev, 0x24); + reg8 |= (1 << 6); /* Set CLKSEL (clock input on pin 1) to 48MHz. */ + pnp_write_config(dev, 0x24, reg8); + pnp_exit_ext_func_mode(dev); +}