diff --git a/src/mainboard/sis/635/Config b/src/mainboard/sis/635/Config new file mode 100644 index 0000000000..31afb46898 --- /dev/null +++ b/src/mainboard/sis/635/Config @@ -0,0 +1,22 @@ +arch i386 +mainboardinit cpu/i386/entry16.inc +mainboardinit cpu/i386/entry32.inc +ldscript cpu/i386/entry16.lds +ldscript cpu/i386/entry32.lds + +mainboardinit superio/sis/950/setup_serial.inc +mainboardinit pc80/serial.inc +mainboardinit arch/i386/lib/console.inc +mainboardinit cpu/p6/earlymtrr.inc + +northsouthbridge sis/635 +nsuperio sis/950 com1={1} floppy=1 lpt=1 + +option ENABLE_FIXED_AND_VARIABLE_MTRRS +option FINAL_MAINBOARD_FIXUP +option HAVE_PIRQ_TABLE=1 +object mainboard.o +object irq_tables.o +keyboard pc80 +cpu p5 +cpu p6 diff --git a/src/mainboard/sis/635/irq_tables.c b/src/mainboard/sis/635/irq_tables.c new file mode 100644 index 0000000000..e19e238740 --- /dev/null +++ b/src/mainboard/sis/635/irq_tables.c @@ -0,0 +1,79 @@ +/* This file was generated by getpir.c, do not modify! + (but if you do, please run checkpir on it to verify) + Contains the IRQ Routing Table dumped directly from your memory , wich BIOS sets up + + Documentation at : http://www.microsoft.com/hwdev/busbios/PCIIRQ.HTM +*/ + +#include + +#ifdef AP_CIRCUIT +/* This PIRQ table is constructed from + * SiS- 635 Single Chipset for Pentium II/ III (Desktop PC) + * Uniprocessor Reference Design Schematics Revision 0.94 (March 5, 2001) + * unfortunatly this is not what the actual board do */ +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32+16*10, /* there can be total 10 devices on the bus */ + 0x00, /* Where the interrupt router lies, Bus 0 */ + 0x10, /* Where the interrupt router lies, Device 2, Function 0 */ + 0x0a20, /* IRQs devoted exclusively to PCI usage, IRQ 11, 10, 5, */ + 0x1039, /* Vendor */ + 0x0008, /* Device */ + 0, /* Crap (miniport) */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0x1c, /* u8 checksum , this hase to set to some value that would + * give 0 after the sum of all bytes for this structure (including checksum) */ + { + {0, 0x40, {{0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}, {0x42, 0xdef8}}, + 0x1, 0}, + {0, 0x38, {{0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}}, + 0x2, 0}, + {0, 0x50, {{0x41, 0xdef8}, {0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}}, + 0x3, 0}, + {0, 0x48, {{0x44, 0xdef8}, {0x41, 0xdef8}, {0x42, 0xdef8}, {0x43, 0xdef8}}, + 0x4, 0}, + {0, 0x60, {{0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}, {0x42, 0xdef8}}, + 0x5, 0}, + {0, 0x58, {{0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}}, + 0x6, 0}, + {0, 0x00, {{0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, + 0x0, 0}, + {0, 0x08, {{0x41, 0xdef8}, {0x42, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, + 0x0, 0}, + {0, 0x10, {{0x41, 0xdef8}, {0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}}, + 0x0, 0}, + {0, 0x18, {{0x43, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, + 0x0, 0}, + } +}; + +#else +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32+16*9, /* there can be total 9 devices on the bus */ + 0x00, /* Where the interrupt router lies (bus) */ + 0x10, /* Where the interrupt router lies (dev) */ + 0, /* IRQs devoted exclusively to PCI usage */ + 0x1039, /* Vendor */ + 0x0008, /* Device */ + 0, /* Crap (miniport) */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0x79, /* u8 checksum , this hase to set to some value that would give + * 0 after the sum of all bytes for this structure (including checksum) */ + { + {0,0x58, {{0x43, 0x16b8}, {0x44, 0x16b8}, {0x41, 0x16b8}, {0x42, 0x16b8}}, 0x1, 0}, + {0,0x48, {{0x42, 0x14b8}, {0x43, 0x16b8}, {0x44, 0x16b8}, {0x41, 0x16b8}}, 0x2, 0}, + {0,0x68, {{0x44, 0x16b8}, {0x41, 0x16b8}, {0x42, 0x16b8}, {0x43, 0x16b8}}, 0x3, 0}, + {0,0x00, {{0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + {0,0x08, {{0x41, 0x16b8}, {0x42, 0x16b8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + {0,0x10, {{0x41, 0x16b8}, {0x42, 0x16b8}, {0x43, 0x16b8}, {0x44, 0x16b8}}, 0x0, 0}, + {0,0x18, {{0x43, 0x16b8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + {0,0x20, {{0x43, 0x16b8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + {0,0x28, {{0x41, 0x16b8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + } +}; + +#endif diff --git a/src/mainboard/sis/635/mainboard.c b/src/mainboard/sis/635/mainboard.c new file mode 100644 index 0000000000..b8addf9e45 --- /dev/null +++ b/src/mainboard/sis/635/mainboard.c @@ -0,0 +1,16 @@ +#include + +void +mainboard_fixup(void) +{ +} + +void +final_mainboard_fixup(void) +{ + void final_southbridge_fixup(void); + + printk_info("SiS 635 (and similar)..."); + + final_southbridge_fixup(); +} diff --git a/src/mainboard/sis/735/Config b/src/mainboard/sis/735/Config new file mode 100644 index 0000000000..02abde883a --- /dev/null +++ b/src/mainboard/sis/735/Config @@ -0,0 +1,23 @@ +arch i386 +mainboardinit cpu/i386/entry16.inc +mainboardinit cpu/i386/entry32.inc +ldscript cpu/i386/entry16.lds +ldscript cpu/i386/entry32.lds + +mainboardinit superio/sis/950/setup_serial.inc +mainboardinit pc80/serial.inc +mainboardinit arch/i386/lib/console.inc +mainboardinit cpu/k7/earlymtrr.inc + +northsouthbridge sis/735 +nsuperio sis/950 com1={1} floppy=1 lpt=1 + +option ENABLE_FIXED_AND_VARIABLE_MTRRS +option FINAL_MAINBOARD_FIXUP +option HAVE_PIRQ_TABLE=1 +object mainboard.o +object irq_tables.o +keyboard pc80 +cpu p5 +cpu p6 +cpu k7 diff --git a/src/mainboard/sis/735/irq_tables.c b/src/mainboard/sis/735/irq_tables.c new file mode 100644 index 0000000000..239ad737f3 --- /dev/null +++ b/src/mainboard/sis/735/irq_tables.c @@ -0,0 +1,69 @@ +/* This file was generated by getpir.c, do not modify! + (but if you do, please run checkpir on it to verify) + Contains the IRQ Routing Table dumped directly from your memory , wich BIOS sets up + + Documentation at : http://www.microsoft.com/hwdev/busbios/PCIIRQ.HTM +*/ + +#include + +#ifdef AP_CIRCUIT +/* This PIRQ table is constructed from + * SiS-735 Single Chipset for AMD-K7 (Desktop PC) + * Uniprocessor Reference Design Schematics Revision 0.91 (May 24, 2001) + * unfortunatly this is not what the actual board do */ +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32+16*5, /* there can be total 5 devices on the bus */ + 0x00, /* Where the interrupt router lies, Bus 0 */ + 0x10, /* Where the interrupt router lies, Device 2, Funxtion 0 */ + 0x0a20, /* IRQs devoted exclusively to PCI usage */ + 0x1039, /* Vendor */ + 0x8, /* Device */ + 0, /* Crap (miniport) */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0xe4, /* u8 checksum , this hase to set to some value that would + * give 0 after the sum of all bytes for this structure (including checksum) */ + { + {0, 0x58, {{0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}, {0x42, 0xdef8}}, 0x1, 0}, + {0, 0x48, {{0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}}, 0x2, 0}, + {0, 0x78, {{0x41, 0xdef8}, {0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}}, 0x3, 0}, + {0, 0x68, {{0x44, 0xdef8}, {0x41, 0xdef8}, {0x42, 0xdef8}, {0x43, 0xdef8}}, 0x4, 0}, + {0, 0x98, {{0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}, {0x42, 0xdef8}}, 0x5, 0}, + {0, 0x88, {{0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}}, 0x6, 0}, + {0, 0x00, {{0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + {0, 0x08, {{0x41, 0xdef8}, {0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}}, 0x0, 0}, + {0, 0x10, {{0x41, 0xdef8}, {0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}}, 0x0, 0}, + {0, 0x18, {{0x43, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + } +}; + +#else + +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, /* u32 signature */ + PIRQ_VERSION, /* u16 version */ + 32+16*7, /* there can be total 9 devices on the bus */ + 0x00, /* Where the interrupt router lies, Bus 0 */ + 0x10, /* Where the interrupt router lies, Device 2, Function 0 */ + 0x0a20, /* IRQs devoted exclusively to PCI usage, 5, 9, 11 */ + 0x1039, /* Vendor */ + 0x0008, /* Device */ + 0, /* Crap (miniport) */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0x41, /* u8 checksum , this hase to set to some value that would give + * 0 after the sum of all bytes for this structure (including checksum) */ + { + /* Mask = 0xdef8, allowing irq 3-7, 1-12, 14,15 */ + {0,0x58, {{0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}, {0x42, 0xdef8}}, 0x1, 0}, + {0,0x48, {{0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}, {0x41, 0xdef8}}, 0x2, 0}, + {0,0x68, {{0x44, 0xdef8}, {0x41, 0xdef8}, {0x42, 0xdef8}, {0x43, 0xdef8}}, 0x3, 0}, + {0,0x00, {{0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + {0,0x08, {{0x41, 0xdef8}, {0x42, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + {0,0x10, {{0x41, 0xdef8}, {0x42, 0xdef8}, {0x43, 0xdef8}, {0x44, 0xdef8}}, 0x0, 0}, + {0,0x18, {{0x43, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}, {0x00, 0xdef8}}, 0x0, 0}, + } +}; + +#endif diff --git a/src/mainboard/sis/735/mainboard.c b/src/mainboard/sis/735/mainboard.c new file mode 100644 index 0000000000..b478ec7e7d --- /dev/null +++ b/src/mainboard/sis/735/mainboard.c @@ -0,0 +1,16 @@ +#include + +void +mainboard_fixup(void) +{ +} + +void +final_mainboard_fixup(void) +{ + void final_southbridge_fixup(void); + + printk_info("SiS 735 (and similar)..."); + + final_southbridge_fixup(); +} diff --git a/src/northsouthbridge/sis/635/635_regs.inc b/src/northsouthbridge/sis/635/635_regs.inc new file mode 100644 index 0000000000..7d81c010cb --- /dev/null +++ b/src/northsouthbridge/sis/635/635_regs.inc @@ -0,0 +1,84 @@ +/* + * 635_regs.inc: Register Recommended Setting for SiS 635 + * + * + * Copyright 2000 Silicon Integrated Systems Corporation + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 635 Programming Giude, Rev. 1.0, Mar. 29, 2001 + * + * $Id$ + */ + +northbridge_init_table: +# High Byte -> Register Low Byte -> Value + /* Host Control */ + .word 0x50ff + .word 0x5147 + .word 0x5271 + .word 0x5383 + .word 0x5403 + .word 0x5501 + .word 0x5688 + .word 0x5788 + + /* DRAM Control */ + .word 0x5800 + .word 0x5a08 + .word 0x5b03 + .word 0x5e03 + + /* ACPI Control */ + .word 0x6a26 + .word 0x6b00 + + /* PCI 33 Control */ + .word 0x8022 + .word 0x8142 + .word 0x8210 + .word 0x8303 + .word 0x8415 + .word 0x8500 + .word 0x8680 + .word 0x8701 + + /* EDB Control */ + .word 0x8820 + .word 0x8904 + .word 0x8b04 + + /* IO Buffer */ + .word 0x9b42 + .word 0x9f20 + .word 0xa042 + .word 0xa12a + .word 0xa222 + .word 0xa301 + + /* PCI 66 Control */ + .word 0xd022 + .word 0xd142 + .word 0xd213 + .word 0xd405 + .word 0xd5ff + .word 0xd6ff + .word 0xd860 + .word 0xd960 + .word 0xdaaa + .word 0xdd88 +northbridge_init_table_end: diff --git a/src/northsouthbridge/sis/635/Config b/src/northsouthbridge/sis/635/Config new file mode 100644 index 0000000000..5a1b31ae0c --- /dev/null +++ b/src/northsouthbridge/sis/635/Config @@ -0,0 +1,5 @@ +option SIS635 +raminit northsouthbridge/sis/635/raminit.inc + +object southbridge.o +object northbridge.o diff --git a/src/northsouthbridge/sis/635/ipl.S b/src/northsouthbridge/sis/635/ipl.S new file mode 100644 index 0000000000..8314749675 --- /dev/null +++ b/src/northsouthbridge/sis/635/ipl.S @@ -0,0 +1,493 @@ +/* + * ipl.S: Initial Program Loader (IPL) for SiS 635 + * + * Copyright 2002 Silicon Integrated Systems Corporation + * Copyright 2002 International Business Machines + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 635 Programming Guide, Rev. 1.0, Mar. 29, 2001 + * 2. System Management Bus Specification Rev 1.1 + * 3. IBM Application Note, DDR SDRAM Module Serial Presence Detect Definitions + * 4. JEDEC Standard, DDR SDRAM Speccification, JESD79, June 2000 + * + * $Id$ + */ + +#include "ipl.h" + +.code16 + +#define SPD_SIZING +#define SIZE_ALL +#define REALLY_COMPACT + +#ifdef STD_FLASH +.org 0xfc00 +#endif + +sis635spd_start: + cli # Disables the maskable + # hardware interrupts. + + movw %cs, %ax # makes data segment == + movw %ax, %ds # code segment + + movw $pre_dram_sizing_table, %si +pre_dram_sizing_start: + lodsw (%si), %ax + testw %ax, %ax + jz pre_dram_sizing_complete + + CALL_SP(write_north_register) + jmp pre_dram_sizing_start + +pre_dram_sizing_complete: + + /* According to JEDEC Spec, we have to drive CKE low for at least 200 mu sec + * to stabilize DDR. Instead of using some kind of busy delay loop, we + * insert some other init stuff before cke_give_up_low and cke_output_normal */ +cke_enable_low: + movw $0x6C30, %ax # Bit 5, Enable CKE output + CALL_BP(write_north_register_or) # Bit 4, CKE Force Low + +acpi_enable: + movw $0x408A, %ax # ACPI Enable. + CALL_SP(write_lpc_register) # (for accessing CKE control) + + movw $0x7550, %ax # Store ACPI Base Address. + CALL_SP(write_lpc_register) # (for accessing CKE control) + + movw $smbus_init_table, %si +smbus_init_start: # inits SMBus Host Controller + lodsw (%si), %ax # for accessing SMBus + testw %ax, %ax + jz smbus_init_complete + + CALL_SP(write_smbus_register) + jmp smbus_init_start + +smbus_init_complete: + +cke_give_up_low: + movw $0x5056, %dx # ACPI 0x56 - legacy event control + inb %dx, %al # Bit 6, Disable Auto-Reset + orb $0x60, %al # Bit 5, CKE control bit for DDR SDRAM + outb %al, %dx + +cke_output_normal: + mov $0x6C, %ah + CALL_SP(read_north_register) + and $0xEF, %al # Bit 4, CKE Normal + CALL_SP(write_north_register) + +/* -----------------------------------------------------------------------------------------*/ + +#ifdef SIZE_ALL + xorw %bx, %bx # clear %fs, %fs is used as "bitmap" of + movw %bx, %fs # install DIMM slot +#endif /* SIZE_ALL */ + +spd_sizing_start: +#ifndef REALLY_COMPACT + movw $0x0320, %ax # Issue an SMB_Kill command to + CALL_BP(sis_set_smbus) # stop all SMBus operation +#endif /* REALLY_COMPACT */ + + movw $0x04a1, %ax # SPD is on SMBUS Address 1010 xyz1 + # where xyz are DIMM Slot Number +#ifdef SIZE_ALL + addb %bh, %al # FIXME, %bh == 0 ?? + addb %bh, %al # Select the DIMM to be SPD-sized. +#endif /* SIZE_ALL*/ + + CALL_BP(sis_set_smbus) + + movb $0x02, %al # Read the RAM Type (SPD byte 2) + CALL_SP(read_spd) # of the dram on current DIMM. + + cmpb $0x07, %bl # If the RAM Type == DDR SDRAM ?? + jne no_sdram # no, exit + + movb $0x03, %al # Read the Row number (SPD byte 3) + CALL_SP(read_spd) # of the dram on current DIMM. + movb %bl, %ch # save the Row number in CH. + + movb $0x04, %al # Read the Column number (SPD byte 4) + CALL_SP(read_spd) # of the dram on current DIMM. + movb %bl, %cl # Save the Column number in CL. + + movb $0x11, %al # Read the Bank number (SPD byte 17) + CALL_SP(read_spd) # of the dram on current DIMM. + +#ifdef SIZE_ALL + movb %bh, %ah # Save the current DIMM slot number in AH +#endif + + cmpb $0x01, %bl + je one_bank + + movw $sdram_type_bank_2, %si + jmp check_row_column +one_bank: + movw $sdram_type_bank_1, %si + +check_row_column: +#ifdef SAFTY_CHECK + cmpb $0x0b, %ch # Row number too small, unsupported. + jb no_sdram + cmpb $0x0d, %ch # Row number too big, unsupported. + jl no_sdram + cmpb $0x08, %cl # Col number too small, unsupported. + jb no_sdram + cmpb $0x0b, %cl # Col number too big, unsupported. + jl no_sdram +#endif /* SAFTY_CHECK */ + + /* This one is DANGEROUS TOO, be careful about OVERFLOW !!! */ + shlb $0x02, %ch # row * 4 + + addb %ch, %cl # column + row *4 + xorb %ch, %ch + + addw %cx, %si # sdram_type_bank[column + row * 4] + movb -52(%si), %cl # sdram_type_bank[column + row * 4 - 52] + +#ifdef SIZE_ALL + movb %ah, %bh # Restore DIMM slot number from AH to BH +#endif /* SIZE_ALL */ + +#ifdef SAFTY_CHECK + cmpb $0xff, %cl # SDRAM type supported ?? + je no_sdram # no, exit +#endif /* SAFTY_CHECK */ + + orb $0x40, %cl # set DDR SDRAM bit + # (reg 0x60~0x63 bit 6) + + movb $0x05, %al # Read the Side number (SPD byte 5) + CALL_SP(read_spd) # of the dram on current DIMM. + + cmpb $0x02, %bl # single or double sided ?? + jne single_side + orb $0x20, %cl # set double side bit + # (reg 0x60~0x63 bit 5) + +single_side: + movb %cl, %al # store DRAM type in al + movb $0x60, %ah # select register 0x60 + +#ifdef SIZE_ALL + addb %bh, %ah # select register 0x60~0x63, accroding + # to DIMM slot number (in BH) +#endif /* SIZE_ALL */ + CALL_SP(write_north_register) # write register 0x60~0x63 for each + # DIMM slot + +#ifdef SIZE_ALL + movw %fs, %ax # enable DIMMx on reg. 0x64 and save + # it in FS + movb $0x01, %bl + movb %bh, %cl + shlb %cl, %bl + orb %bl, %al + movw %ax, %fs +no_sdram: + incb %bh + cmpb $0x04, %bh # total 4 DIMM slots supported + jb spd_sizing_start + + movw %fs, %ax + movb $0x64, %ah +#else /* !SIZE_ALL */ +no_sdram: + movw $0x6401, %ax # enable DIMM 0 +#endif /* SIZE_ALL */ + + CALL_SP(write_north_register) # write DRAM status register 0x64 + +/* -----------------------------------------------------------------------------------------*/ + + /* Start JEDEC DDR initialization sequence */ +jedec_ddr_init_seq: + movb NO_OP, %bl + CALL_BP(dram_ctrl_cmd) + + movw $ddr_init_table, %si +init_ddr_sdram: + lodsb (%si), %al + testb %al, %al + jz ddr_init_complete + + movb %al, %bl + CALL_BP(dram_ctrl_cmd) + jmp init_ddr_sdram + +ddr_init_complete: + + movw $post_dram_init_table, %si +post_dram_init_start: + lodsw (%si), %ax + testw %ax, %ax + jz post_dram_init_complete + + CALL_SP(write_north_register) + jmp post_dram_init_start + +post_dram_init_complete: + +/* -----------------------------------------------------------------------------------------*/ + +sis635ipl_start: + /* O.K. we have DRAM now, so set up STACK for CALL/RET */ + movw $DOC_STACK_SEG, %ax + movw %ax, %ss + movw $SPL_RAM_SEG, %ax + movw %ax, %es + xorw %sp, %sp # clear %sp + +#ifdef STD_FLASH +#include "rom/std_flash.inc" +#else /* !STD_FLASH */ +#include "unlock_flash.inc" +#if defined(USE_DOC_MIL) || defined(USE_DOC_2000_TSOP) +# include "rom/doc_mil.inc" +#else defined(USE_DOC_MIL_PLUS) +# include "rom/doc_mil_plus.inc" +#endif +#endif /* STD_FLASH */ + +sis635ipl_end: + jmp spl_vector # jump to SPL vector + + +/* -----------------------------------------------------------------------------------------*/ + +write_north_register: + /* Input: AH - register number. AL - register value. + Chnaged: CX, EDX */ + movl $NORTH_BRIDGE_BASE_ADDR, %edx + jmp write_common + +write_lpc_register: + /* Input: AH - register number. AL - register value. + Chnaged: CX, EDX */ + movl $LPC_BRIDGE_BASE_ADDR, %edx + jmp write_common + +write_smbus_register: + /* Input: AH - register number. AL - register value. + Chnaged: CX, EDX */ + movl $SMBUS_HOST_BASE_ADDR, %edx + jmp write_common + +write_common: + movw %ax, %cx # Save %ax to %cx. + + movzbl %ch, %eax # add register address to + addl %edx, %eax # PCI base address + + movw $PCI_COMMAND_PORT, %dx + outl %eax, %dx + + movw $PCI_DATA_PORT, %dx + andb $0x03, %al + addb %al, %dl + movw %cx, %ax + outb %al, %dx + RET_SP # End of write_[pci|smbus]_reg + +/* -----------------------------------------------------------------------------------------*/ +read_north_register: + /* Input: AH - register number. + Output AL - register value. + Chnaged: CX, EDX */ + movl $NORTH_BRIDGE_BASE_ADDR, %edx + +read_common: + movw %ax, %cx # Save %ax to %cx. + + movzbl %ch, %eax # add register address to + addl %edx, %eax # PCI base address + + movw $PCI_COMMAND_PORT, %dx + outl %eax, %dx + + movw $PCI_DATA_PORT, %dx + andb $0x03, %al + addb %al, %dl + inb %dx, %al + + movb %ch, %ah # Resotre register number to %ah + + RET_SP # End of write_[pci|smb] + +write_north_register_or: + /* Input: AH - register number. AL - register mask. + Chnaged: CX, EDX*/ + CALL_SP(read_north_register) # %cl == old %al + orb %cl, %al + CALL_SP(write_north_register) + RET_BP + +/* -----------------------------------------------------------------------------------------*/ + +dram_ctrl_cmd: + /* Input: BL - DRAM COMMAND. + Chnaged: AX, CX, EDX*/ + movb $0x5C, %ah # read 0x5C DRAM Init Control + CALL_SP(read_north_register) + andb $0x07, %al # Clear Command bits + orb %bl, %al # Set DRAM command + CALL_SP(write_north_register) + orb $0x08, %al # Issue DRAM Command + CALL_SP(write_north_register) + RET_BP + +/* -----------------------------------------------------------------------------------------*/ + +read_spd: + /* Input: AH = 05h, AL = byte number of SPD to be read. + Output: BL = The value of specified SPD byte. */ + movb $0x05, %ah # set SMB Command == byte address + CALL_BP(sis_set_smbus) + + movw $0x0312, %ax # Start, R/W byte Data + CALL_BP(sis_set_smbus) + +wait_for_smbus_read: + movb $0x80, %dl # Read SMBus status + inb %dx, %al + + testb $0x02, %al # if device errors + jnz read_spd_fail # then skip read SPD + + testb $0x08, %al # if not complete + jz wait_for_smbus_read # then wait SPD data complete + +read_spd_fail: + movb $0x08, %ah + +sis_get_smbus: + /* Input: AH - register index. + Output: BL - register value. */ + addb %ah, %dl # read SMBus byte 0 + inb %dx, %al + movb %al, %bl # return result in BL + + movw $0x00ff, %ax + CALL_BP(sis_set_smbus) # clear ACPI 80h status + + RET_SP # End of read_spd + +sis_set_smbus: + /* Input: AH - register index. AL - register value. */ + movw $SMB_BASE_ADDR, %dx + addb %ah, %dl + outb %al, %dx + RET_BP # End of sis_set_smbus + +/* -----------------------------------------------------------------------------------------*/ + +sdram_type_bank_1: +# Column Number 8 9 10 11 Row Number + .byte 0b0000, 0b0100, 0b1000, 0xff # 11 + .byte 0xff, 0xff, 0xff, 0xff # 12 + .byte 0b0001, 0b0101, 0b1001, 0xff # 13 + +sdram_type_bank_2: +# Column Number 8 9 10 11 Row Number + .byte 0b1100, 0xff, 0xff, 0xff # 11 + .byte 0b0010, 0b0110, 0b1010, 0b1110 # 12 + .byte 0b0011, 0b0111, 0b1011, 0b1111 # 13 +# FixMe: Bank 2 x Column 12 x Row 13 == 1GB + +/* -----------------------------------------------------------------------------------------*/ + +pre_dram_sizing_table: +# High Byte -> Register Low Byte -> Value + /* DRAM Control */ + .word 0x5929 # CAS Latency = 2.5T + .word 0x5c12 # MD/DQS Input Enable for DDR + .word 0x5dc0 # Refresh Cycle Disabled + + /* ACPI Control */ + .word 0x6801 # ACPI Enable. + .word 0x6950 # Store ACPI Base Address. + + /* IO Buffer */ + .word 0x9920 # DDR IO Input Mode ==> Differential + .word 0x9ab8 # Enable DQS signal delay + + .word 0x0000 /* Null, End of table */ + +post_dram_init_table: +# High Byte -> Register Low Byte -> Value + .word 0x0407 # Enable IO/MEM Space, BM DMA + .word 0x0d20 + + /* DRAM Control */ + .word 0x5dc1 # Refresh Cycle Enabled + + .word 0x0000 /* Null, End of table */ + +smbus_init_table: +# High Byte -> Register Low Byte -> Value + .word 0x0401 # enable IO space + .word 0x2080 # SMBus Base address = + .word 0x2150 # 0x5080 + .word 0x4001 # enable SMBus Host Controller + .word 0x0000 /* Null, End of table */ + +ddr_init_table: + .byte PALL # Percharge All + .byte DLL_EN_N # DLL Enable Normal + .byte DLL_RESET # DLL Reset + .byte PALL # Precharge All + .byte REF # Refresh + .byte REF # Refresh + .byte MRS # Mode Register Set + .byte 0x0000 /* Null, End of table */ + +/* -----------------------------------------------------------------------------------------*/ +#ifdef STD_FLASH + .org 0xfff0 +reset_vector: + .byte 0xea # jmp to f000:fc00, where IPL + .word 0xfc00, 0xf000 # starts in Standard Flash +#else /* !STD_FLASH i.e. DoC Mil */ +#if defined(USE_DOC_MIL) + .org 0x1f0 +#elif defined(USE_DOC_2000_TSOP) || defined(USE_DOC_MIL_PLUS) + .org 0x3f0 +#endif +reset_vector: + .byte 0xea # jmp to fc00:0000, where IPL + .word 0x0000, DOC_WIN_SEG # starts in DoC +#endif /* STD_FLASH */ + +spl_vector: + .byte 0xea # jmp to 8000:0000, where SPL + .word 0x0000, SPL_RAM_SEG # (LinuxBIOS) starts in RAM + +/* -----------------------------------------------------------------------------------------*/ + +sis950_init_table: + .byte 0x87, 0x01, 0x55, 0x55, 0x24 + +end: + hlt diff --git a/src/northsouthbridge/sis/635/ipl.h b/src/northsouthbridge/sis/635/ipl.h new file mode 100644 index 0000000000..57c8d66a84 --- /dev/null +++ b/src/northsouthbridge/sis/635/ipl.h @@ -0,0 +1,67 @@ +#define PCI_COMMAND_PORT 0xcf8 +#define PCI_DATA_PORT 0xcfc + +#define NORTH_BRIDGE_BASE_ADDR 0x80000000 /* Bus 0, Device 0, Function 0 */ +#define LPC_BRIDGE_BASE_ADDR 0x80001000 /* Bus 0, Device 2, Function 0 */ +#define SMBUS_HOST_BASE_ADDR 0x80001100 /* Bus 0, Device 2, Function 1 */ + +#define ACPI_BASE_ADDR 0x5000 +#define SMB_BASE_ADDR 0x5080 + +/* DDR Initialization Register and Command */ +#define DRAM_INIT_REG 0x5c +#define DQS_ENABLE 0x02 +#define DDR_CMD_ISSUE 0x08 +#define NO_OP 0x00 +#define PALL 0x10 +#define MRS 0x20 +#define REF 0x30 +#define DLL_EN_N 0x40 +#define DLL_EN_W 0x50 +#define DLL_RESET 0x60 +#define DLL_DISABLE 0x70 + +#define DDR_CMD DDR_CMD_ISSUE | DQS_ENABLE +#define DDR_CMD_PALL (DRAM_INIT_REG << 8 | PALL | DDR_CMD) +#define DDR_CMD_DLL_EN_N (DRAM_INIT_REG << 8 | DLL_EN_N | DDR_CMD) +#define DDR_CMD_DLL_RESET (DRAM_INIT_REG << 8 | DLL_RESET | DDR_CMD) +#define DDR_CMD_REF (DRAM_INIT_REG << 8 | REF | DDR_CMD) +#define DDR_CMD_MRS (DRAM_INIT_REG << 8 | MRS | DDR_CMD) + +#define ENABLE_FRESH_CYCLE 0x5d01 + +#define DOC_WIN_SEG 0xfe00 +#define DOC_STACK_SEG 0x0400 +#define SPL_RAM_SEG 0x8000 + +#if defined(USE_DOC_2000_TSOP) +#define DOC_SPL_START_PAGE 4 /* 0-3 for IPL (each of 1KB size) */ +#else /* defined (USE_DOC_MIL) */ +#define DOC_SPL_START_PAGE 2 /* 0,1 for IPL (each of 512B size) */ +#endif + +#define DOC_SPL_SIZE_IN_PAGE 128 - DOC_SPL_START_PAGE /* 1 page = 512 bytes, total 63kB */ + +/* Pseudo Call and Return macros */ +#define RET_LABEL(label) \ + jmp label##_done + +#define CALL_LABEL(label) \ + jmp label ;\ +label##_done: + +#define CALL_SP(func) \ + lea 0f, %sp ; \ + jmp func ; \ +0: + +#define RET_SP \ + jmp *%sp + +#define CALL_BP(func) \ + lea 0f, %bp ; \ + jmp func ; \ +0: + +#define RET_BP \ + jmp *%bp diff --git a/src/northsouthbridge/sis/635/northbridge.c b/src/northsouthbridge/sis/635/northbridge.c new file mode 100644 index 0000000000..893f5ad506 --- /dev/null +++ b/src/northsouthbridge/sis/635/northbridge.c @@ -0,0 +1,109 @@ +/* + * northbridge.c: SiS 635 Northbridge Initialization + * + * Copyright 2002 International Business Machines + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 635 Programing Guide + * + */ + +#include +#include +#include +#include +#include + +/* these functions query the hardware to figure out how much ram is in + * the machine. They then place that information in the parameter block. + * This is kind of schizophrenic, but we do it this way because the + * functions that actually set the registers are kind of hairy, and + * we're not sure they can carry the full burden of also passing on + * the size information to the rest of the bootstrap. Besides, querying + * hardware for ram sizes is trivial. + */ + +/* table for calculate the DRAM size, the unit is Mega Bytes */ +const static int ramsizes[16] = +{ + 8, 32, 32, 64, 16, 64, 64, 128, + 32, 128, 128, 256, 16, 1024, 256, 512 +}; +#define SIS635_BANKENABLE 0x64 +#define SIS635_BANK0 0x60 +#define SIS635_BANK1 0x61 +#define SIS635_BANK2 0x62 +#define SIS635_BANK3 0x63 +unsigned +long sizeram() +{ + struct pci_dev *pcidev; + unsigned int dimm_slot, dimm_reg, sides; + unsigned long total_size; + u8 dram_status, dimm_status; + + if ((pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_635, NULL)) == NULL) + return 0; + + pci_read_config_byte(pcidev, SIS635_BANKENABLE, &dram_status); + dimm_status = dram_status & 0xF; + + for (dimm_slot = 0, total_size = 0, dimm_reg = SIS635_BANK0; + dimm_reg <= SIS635_BANK3; dimm_slot++, dimm_reg++) { + u8 regval; + if ((dimm_status & (1 << dimm_slot)) == 0) + /* this DIMM slot does not have SDRAM installed */ + continue; + + pci_read_config_byte(pcidev, dimm_reg, ®val); + + /* is this DIMM single or double sided ?? */ + if (regval & 0x20) + sides = 2; + else + sides = 1; + + /* low-order 4 bits are a ram size */ + total_size += (ramsizes[regval & 0xf] * sides); + } + + /* return the memory size in KB */ + total_size *= 1024; + return total_size; +} + +#ifdef HAVE_FRAMEBUFFER +void framebuffer_on() +{ + unsigned long devfn; + u16 command; + + devfn = PCI_DEVFN(2, 0); + + /* Enable VGA Palette Snoop */ + pcibios_read_config_word(0, devfn, 0x04, &command); + command |= 0x20; + pcibios_write_config_word(0, devfn, 0x04, command); + + /* enable legacy VGA IO (0x3B0 - 0x3BB, 0x3C0 - 0x3DF) and MEM (0xA0000 - 0xBFFFF), + needed for XFree86 3.3.6 */ + pcibios_read_config_word(0, devfn, 0x3e, &command); + command |= 0x08; + pcibios_write_config_word(0, devfn, 0x3e, command); +} +#endif /* HAVE_FRAMEBUFFER */ diff --git a/src/northsouthbridge/sis/635/raminit.inc b/src/northsouthbridge/sis/635/raminit.inc new file mode 100644 index 0000000000..1846b906f3 --- /dev/null +++ b/src/northsouthbridge/sis/635/raminit.inc @@ -0,0 +1,66 @@ +/* + * raminit.inc: Setting registers to their recommended values for SiS 635. + * Since we have inited the DRAM in IPL it is not neceressary + * to do "raminit" here any more. + * + * + * Copyright 2000 Silicon Integrated Systems Corporation + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 635 Programming Guide, Rev. 1.0, Mar. 29, 2001 + * $Id$ + */ + +#define PCI_COMMAND_PORT 0xcf8 +#define PCI_DATA_PORT 0xcfc + +#define NORTH_BRIDGE_BASE_ADDR 0x80000000 +#define LPC_BRIDGE_BASE_ADDR 0x80000800 + +register_setting_start: + movl $northbridge_init_table, %esi + movl $(northbridge_init_table_end - northbridge_init_table), %ecx + shrl $0x01, %ecx + +init_northbridge: + lodsw (%esi), %ax # load the register address/value to %ax + +write_northbridge_register: + /* Input: AH - register number. AL - register value. */ + movl $NORTH_BRIDGE_BASE_ADDR, %edx + + movl %eax, %ebx # Save %eax to %ebx. + + movzbl %bh, %eax # add register address to + addl %edx, %eax # PCI base address + + movw $PCI_COMMAND_PORT, %dx + outl %eax, %dx + + movw $PCI_DATA_PORT, %dx + andb $0x03, %al + addb %al, %dl + movb %bl, %al + outb %al, %dx + loopnz init_northbridge + + jmp register_setting_end + +#include "635_regs.inc" + +register_setting_end: diff --git a/src/northsouthbridge/sis/635/southbridge.c b/src/northsouthbridge/sis/635/southbridge.c new file mode 100644 index 0000000000..145691d237 --- /dev/null +++ b/src/northsouthbridge/sis/635/southbridge.c @@ -0,0 +1,294 @@ +/* + * southbridge.c: Southbridge Initialization For SiS 635 + * + * Copyright 2002 International Business Machines + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 635 Programing Guide + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define BYTE sizeof(u8) +#define WORD sizeof(u16) +#define DBLE sizeof(u32) +#define IDE_REG_EXTENDED_OFFSET (0x200u) +#define IDE_REG_SECTOR_COUNT(base) ((base) + 2u) +#define IDE_REG_CONTROL(base) ((base) + IDE_REG_EXTENDED_OFFSET + 6u) +#define IDE_BASE1 (0x1F0u) /* primary controller */ +#define ASIZE(x) (sizeof(x)/sizeof((x)[0])) + +typedef struct { + u8 size; + u8 regno; + u32 andval; + u32 orval; +} initreg_t; + +static const initreg_t ide_init[] = { + /* + * BUS(0), DEVICE(0), FUNCTION(1): IDE Interface. Bridge + */ + /* SIZE REG AND-MASK OR-MASK */ + { WORD, 0x04, 0x00, 0x0007 }, /* Command Register. sets mem+ */ + { WORD, 0x06, 0x00, 0x3000 }, /* Status reg, clear aborts. */ + { WORD, 0x09, 0x0A, 0x00 }, /* Programming interface = Compatible mode. */ + { BYTE, 0x0D, 0x00, 0x80 }, /* Latency Timer */ + /* We let the pci enumerator assign these. */ + // { DBLE, 0x10, 0x0, 0x1F1 }, /* Primary channel base addr. */ + // { DBLE, 0x14, 0x0, 0x3F5 }, /* Primary channel control base addr. */ + // { DBLE, 0x18, 0x0, 0x171 }, /* Secondary channel base addr. */ + // { DBLE, 0x1C, 0x0, 0x375 }, /* Secondary channel control base addr. */ + // { DBLE, 0x20, 0x0, 0x4001 }, /* Control register base addr. */ + { WORD, 0x2C, 0x00, 0x1039 }, /* Subsystem vendor ID. */ + { WORD, 0x2E, 0x00, 0x5513 }, /* Subsystem ID. */ + { BYTE, 0x3c, 0x00, 0x0e }, /* reserved don't do this, sets irq 14 */ + { BYTE, 0x40, 0x00, 0x44 }, /* Primary master data active/recovery time. PIO Mode 2 */ + { BYTE, 0x41, 0x00, 0x85 }, /* Primary master UDMA cycle time. UDMA Mode 2 */ + { BYTE, 0x42, 0x00, 0x00 }, /* Primary slave data recovery time. */ + { BYTE, 0x43, 0x00, 0x00 }, /* Primary slave data active time. */ + { BYTE, 0x44, 0x00, 0x00 }, /* Secondary master data recovery time. */ + { BYTE, 0x45, 0x00, 0x00 }, /* Secondary master data active time. */ + { BYTE, 0x46, 0x00, 0x00 }, /* Secondary slave data recovery time. */ + { BYTE, 0x47, 0x00, 0x00 }, /* Secondary slave data active time. */ + { BYTE, 0x48, 0x00, 0x08 }, /* Read/Write FIFO Threshold = 1/4 */ + { BYTE, 0x4A, 0x40, 0xe6 }, /* Enable Bus Master, Fast postwrite, IDE 0,1 */ + { BYTE, 0x4B, 0x00, 0x11 }, /* Enable Postwrite and Prefech for IDE0, Master */ + { WORD, 0x4C, 0x00, 0x0200 }, /* Prefetch count of primary. */ + { WORD, 0x4E, 0x00, 0x0200 }, /* Prefetch count of secondary. */ + { BYTE, 0x52, 0xFF, 0x14 } /* Miscelaneous control (Only Doc). */ +}; + +void ide_fixup(void) +{ + + struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, + (void *) NULL); + int i; + u8 val8; + u16 val16; + u32 val32; + + int initlen = ASIZE(ide_init); + const initreg_t * inittab = ide_init; + + printk_info ("Entering the initregs process\n"); + + for (i = 0; i < initlen; ++i) { + u16 regno = inittab[i].regno; + switch (inittab[i].size) { + case BYTE: + pci_read_config_byte(dev, regno, &val8); + val8 = (val8 & inittab[i].andval) | inittab[i].orval; + pci_write_config_byte(dev, regno, val8); + break; + case WORD: + pci_read_config_word(dev, regno, &val16); + val16 = (val16 & inittab[i].andval) | inittab[i].orval; + pci_write_config_word(dev, regno, val16); + break; + case DBLE: + pci_read_config_dword(dev, regno, &val32); + val32 = (val32 & inittab[i].andval) | inittab[i].orval; + break; + + default: + outb_p(0xEE,0x80); + while(1); + break; + } + } +} + +void keyboard_on() +{ + u8 regval; + struct pci_dev *pcidev; + void pc_keyboard_init(void); + + /* turn on sis635 keyboard/mouse controller */ + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, (void *)NULL); + if (pcidev != NULL) { + /* Register 0x47, Keyboard Controller */ + pci_read_config_byte(pcidev, 0x47, ®val); + /* enable both integrated keyboard and PS/2 mouse controller */ + regval |= 0x0c; + pci_write_config_byte(pcidev, 0x47, regval); + } + pc_keyboard_init(); +} + +void nvram_on() +{ + struct pci_dev *pcidev; + u8 tmp; + + /* turn on sis635 nvram. */ + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, (void *)NULL); + + if (pcidev != NULL) { + printk_info("Enabling nvram\n"); + /* Enable FFF80000 to FFFFFFFF decode. You have to also enable + PCI Posted write for devices on sourthbridge */ + pci_read_config_byte(pcidev, 0x40, &tmp); + tmp |= 0x3; + pci_write_config_byte(pcidev, 0x40, tmp); + } + +#if !defined(STD_FLASH) + /* turn off nvram shadow in 0xc0000 ~ 0xfffff, i.e. accessing segment C - F + is actually to the DRAM not NVRAM. For 512KB NVRAM case, this one should be + disabled */ + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_635, (void *)NULL); + if (pcidev != NULL) { + /* read cycle goes to System Memory */ + pci_write_config_word(pcidev, 0x70, 0x1fff); + /* write cycle goest to System Memory */ + pci_write_config_word(pcidev, 0x72, 0x1fff); + printk_debug("Shadow memory disabled in SiS 635\n"); + + } +#endif +} + +/* serial_irq_fixup: Enable Serial Interrupt. Serial interrupt is the IRQ line from SiS 950 + * LPC to Host Controller. Serial IRQ is neceressary for devices on SiS 950 + * ie.e floppy, COM, LPT etc + */ +static void +serial_irq_fixedup(void) +{ + struct pci_dev *pcidev; + + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, (void *)NULL); + if (pcidev != NULL) { + /* enable Serial Interrupt (SIRQ) */ + pci_write_config_byte(pcidev, 0x69, 0x80); + pci_write_config_byte(pcidev, 0x67, 0x10); + } +} + +/* timer0_fixup: Fix up the Timer 0 of 8254 Programmable Timer + * + * The timer 0 is used to generate the 18.2 Hz, IRQ 0 timer event and used by system + * to update date/time. + * + * FixME: Should be program timer 1 for DRAM refresh too ?? + */ +static void +timer0_fixup(void) +{ + /* select Timer 0, 16 Bit Access, Mode 3, Binary */ + outb_p(0x43, 0x36); + + /* Load LSB, 0x00 */ + outb_p(0x40, 0x00); + + /* Load MSB, 0x00 */ + outb_p(0x40, 0x00); +} + +/* rtc_fixup: Fix up the Real Time Clock + * + * The Real Time Clock updates the day/time information in the CMOS RAM every second. + * The clock diveder has to be programmed correctly or the RTC will update the CMOS + * in incorrect time interval (i.e. more or less then 1Sec in "wall clock"). + * + * FixME: Where does the CMOS stroe Y2K information and how does Linux handle it ?? + */ +static void +rtc_fixup(void) +{ + volatile u8 dummy; + u8 regval; + struct pci_dev *isa_bridge; + + isa_bridge = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, + (void *)NULL); + if (isa_bridge != NULL) { + /* Register 0x48, Enable internal RTC */ + pci_read_config_byte(isa_bridge, 0x48, ®val); + pci_write_config_byte(isa_bridge, 0x48, regval | 0x10); + } + + /* Select Normal Colok Divider, 978 us interrupt */ + outb_p(0x0A, 0x70); + outb_p(0x26, 0x71); + + /* Select 24 HR time */ + outb_p(0x0B, 0x70); + outb_p(0x02, 0x71); + + /* Clear Checksum Error */ + outb_p(0x0D, 0x70); + dummy = inb_p(0x71); +} + +static void +acpi_fixup(void) +{ + struct pci_dev *pcidev; + + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, (void *)NULL); + if (pcidev != NULL) { + unsigned char val; + unsigned short acpibase = 0xc000, temp; + + // the following is to turn off software watchdogs. + // we co-op the address space from c000-cfff here. Temporarily. + // Later, we need a better way to do this. + // But since Linux doesn't even understand this yet, no issue. + // Set a base address for ACPI of 0xc000 + pci_write_config_word(pcidev, 0x74, acpibase); + + // now enable acpi + pci_read_config_byte(pcidev, 0x40, &val); + val |= 0x80; + pci_write_config_byte(pcidev, 0x40, val); + + /* Disable Auto-Reset */ + val = inb(acpibase + 0x56); + outw(val | 0x40, acpibase + 0x56); + /* Disable Software Watchdog */ + outb(0, acpibase + 0x4b); + } else { + printk_emerg("Can't find south bridge!\n"); + } + +} + +// simple fixup (which we hope can leave soon) for the sis southbridge part +void +final_southbridge_fixup() +{ + timer0_fixup(); + rtc_fixup(); + nvram_on(); + acpi_fixup(); + ide_fixup(); + + printk_debug("Southbridge fixup done for SIS 635\n"); +} + diff --git a/src/northsouthbridge/sis/635/unlock_flash.inc b/src/northsouthbridge/sis/635/unlock_flash.inc new file mode 100644 index 0000000000..e079e5b4e2 --- /dev/null +++ b/src/northsouthbridge/sis/635/unlock_flash.inc @@ -0,0 +1,7 @@ + movw $sis950_init_table, %si # unlock SiS 950 LPC + movw $0x05, %cx # select Clock Selection + movw $0x2e, %dx # and Flash ROM I/F + rep + outsb + movb $0xfd, %al # enable write, CLKIN = 24 MHZ + outb %al, $0x2f diff --git a/src/northsouthbridge/sis/735/735_regs.inc b/src/northsouthbridge/sis/735/735_regs.inc new file mode 100644 index 0000000000..75915b1b3e --- /dev/null +++ b/src/northsouthbridge/sis/735/735_regs.inc @@ -0,0 +1,88 @@ +/* + * 735_regs.inc: Register Recommended Setting for SiS 735 + * + * + * Copyright 2000 Silicon Integrated Systems Corporation + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 735 Programming Guide, Rev. 1.0, Apr. 16, 2001 + * + * $Id$ + */ + +northbridge_init_table: +# High Byte -> Register Low Byte -> Value + /* BIU Control */ + .word 0x5007 + .word 0x51a4 + .word 0x5277 + .word 0x53f7 + .word 0x54aa + .word 0x55d4 + .word 0x56e8 + .word 0x57f0 + + /* DRAM Control */ + .word 0x5a38 + .word 0x5b03 + .word 0x5e03 + + /* ACPI Control */ + .word 0x6a18 + .word 0x6b03 + + /* PCI 33 Control */ + .word 0x8002 + .word 0x8140 + .word 0x8210 + .word 0x8300 + .word 0x8415 + .word 0x8500 + .word 0x8680 + .word 0x8701 + + /* EDB Control */ + .word 0x8820 + .word 0x890c + .word 0x8b04 + + /* IO Buffer */ + .word 0x9b40 + .word 0x9f10 + .word 0xa041 + .word 0xa111 + .word 0xa221 + .word 0xa301 + .word 0xa4aa + .word 0xa5aa + + /* S2K Interface */ + .word 0xb836 + .word 0xb99a + .word 0xba48 + .word 0xbbfa + .word 0xbc16 + + /* PCI 66 Control */ + .word 0xd002 + .word 0xd231 + .word 0xd409 + .word 0xd5ff + .word 0xd6ff + .word 0xdd88 +northbridge_init_table_end: diff --git a/src/northsouthbridge/sis/735/Config b/src/northsouthbridge/sis/735/Config new file mode 100644 index 0000000000..3ffd3a5cd8 --- /dev/null +++ b/src/northsouthbridge/sis/735/Config @@ -0,0 +1,5 @@ +option SIS735 +raminit northsouthbridge/sis/735/raminit.inc + +object southbridge.o +object northbridge.o diff --git a/src/northsouthbridge/sis/735/ipl.S b/src/northsouthbridge/sis/735/ipl.S new file mode 100644 index 0000000000..2f49109acb --- /dev/null +++ b/src/northsouthbridge/sis/735/ipl.S @@ -0,0 +1,503 @@ +/* + * ipl.S: Initial Program Loader (IPL) for SiS 735 + * + * Copyright 2002 Silicon Integrated Systems Corporation + * Copyright 2002 International Business Machines + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 735 Programming Guide, Rev. 1.0, Apr. 16, 2001 + * 2. System Management Bus Specification Rev 1.1 + * 3. IBM Application Note, DDR SDRAM Module Serial Presence Detect Definitions + * 4. JEDEC Standard, DDR SDRAM Speccification, JESD79, June 2000 + * + * $Id$ + */ + +#include "ipl.h" + +.code16 + +//#define SPD_SIZING +#define SIZE_ALL +#define REALLY_COMPACT + +#ifdef STD_FLASH +.org 0xfc00 +#endif + +sis735spd_start: + cli # Disables the maskable + # hardware interrupts. + + movw %cs, %ax # makes data segment == + movw %ax, %ds # code segment + + movw $pre_dram_sizing_table, %si +pre_dram_sizing_start: + lodsw (%si), %ax + testw %ax, %ax + jz pre_dram_sizing_complete + + CALL_SP(write_north_register) + jmp pre_dram_sizing_start + +pre_dram_sizing_complete: + + /* According to JEDEC Spec, we have to drive CKE low for at least 200 mu sec + * to stabilize DDR. Instead of using some kind of busy delay loop, we + * insert some other init stuff before cke_give_up_low and cke_output_normal */ +cke_enable_low: + movw $0x6B30, %ax # Bit 5, Enable CKE output + CALL_BP(write_north_register_or) # Bit 4, CKE Force Low + +acpi_enable: + movw $0x408A, %ax # ACPI Enable. + CALL_SP(write_lpc_register) # (for accessing CKE control) + + movw $0x7550, %ax # Store ACPI Base Address. + CALL_SP(write_lpc_register) # (for accessing CKE control) + + movw $smbus_init_table, %si +smbus_init_start: # inits SMBus Host Controller + lodsw (%si), %ax # for accessing SMBus + testw %ax, %ax + jz smbus_init_complete + + CALL_SP(write_smbus_register) + jmp smbus_init_start + +smbus_init_complete: + +cke_give_up_low: + movw $0x5056, %dx # ACPI 0x56 - legacy event control + inb %dx, %al # Bit 6, Disable Auto-Reset + orb $0x60, %al # Bit 5, CKE control bit for DDR SDRAM + outb %al, %dx + +cke_output_normal: + mov $0x6B, %ah + CALL_SP(read_north_register) + and $0xEF, %al # Bit 4, CKE Normal + CALL_SP(write_north_register) + +/* -----------------------------------------------------------------------------------------*/ +#ifndef SPD_SIZING +ddr_size: + movw $0x614A, %ax + CALL_SP(write_north_register) + + movw $0x6402, %ax + CALL_SP(write_north_register) +#else + +#ifdef SIZE_ALL + xorw %bx, %bx # clear %fs, %fs is used as "bitmap" of + movw %bx, %fs # install DIMM slot +#endif /* SIZE_ALL */ + +spd_sizing_start: +#ifndef REALLY_COMPACT + movw $0x0320, %ax # Issue an SMB_Kill command to + CALL_BP(sis_set_smbus) # stop all SMBus operation +#endif /* REALLY_COMPACT */ + + movw $0x04a1, %ax # SPD is on SMBUS Address 1010 xyz1 + # where xyz are DIMM Slot Number +#ifdef SIZE_ALL + addb %bh, %al # FIXME, %bh == 0 ?? + addb %bh, %al # Select the DIMM to be SPD-sized. +#endif /* SIZE_ALL*/ + + CALL_BP(sis_set_smbus) + + movb $0x02, %al # Read the RAM Type (SPD byte 2) + CALL_SP(read_spd) # of the dram on current DIMM. + + cmpb $0x07, %bl # If the RAM Type == DDR SDRAM ?? + jne no_sdram # no, exit + + movb $0x03, %al # Read the Row number (SPD byte 3) + CALL_SP(read_spd) # of the dram on current DIMM. + movb %bl, %ch # save the Row number in CH. + + movb $0x04, %al # Read the Column number (SPD byte 4) + CALL_SP(read_spd) # of the dram on current DIMM. + movb %bl, %cl # Save the Column number in CL. + + movb $0x11, %al # Read the Bank number (SPD byte 17) + CALL_SP(read_spd) # of the dram on current DIMM. + +#ifdef SIZE_ALL + movb %bh, %ah # Save the current DIMM slot number in AH +#endif + + cmpb $0x01, %bl + je one_bank + + movw $sdram_type_bank_2, %si + jmp check_row_column +one_bank: + movw $sdram_type_bank_1, %si + +check_row_column: +#ifdef SAFTY_CHECK + cmpb $0x0b, %ch # Row number too small, unsupported. + jb no_sdram + cmpb $0x0d, %ch # Row number too big, unsupported. + jl no_sdram + cmpb $0x08, %cl # Col number too small, unsupported. + jb no_sdram + cmpb $0x0b, %cl # Col number too big, unsupported. + jl no_sdram +#endif /* SAFTY_CHECK */ + + /* This one is DANGEROUS TOO, be careful about OVERFLOW !!! */ + shlb $0x02, %ch # row * 4 + + addb %ch, %cl # column + row *4 + xorb %ch, %ch + + addw %cx, %si # sdram_type_bank[column + row * 4] + movb -52(%si), %cl # sdram_type_bank[column + row * 4 - 52] + +#ifdef SIZE_ALL + movb %ah, %bh # Restore DIMM slot number from AH to BH +#endif /* SIZE_ALL */ + +#ifdef SAFTY_CHECK + cmpb $0xff, %cl # SDRAM type supported ?? + je no_sdram # no, exit +#endif /* SAFTY_CHECK */ + + orb $0x40, %cl # set DDR SDRAM bit + # (reg 0x60~0x63 bit 6) + + movb $0x05, %al # Read the Side number (SPD byte 5) + CALL_SP(read_spd) # of the dram on current DIMM. + + cmpb $0x02, %bl # single or double sided ?? + jne single_side + orb $0x20, %cl # set double side bit + # (reg 0x60~0x63 bit 5) + +single_side: + movb %cl, %al # store DRAM type in al + movb $0x60, %ah # select register 0x60 + +#ifdef SIZE_ALL + addb %bh, %ah # select register 0x60~0x63, accroding + # to DIMM slot number (in BH) +#endif /* SIZE_ALL */ + CALL_SP(write_north_register) # write register 0x60~0x63 for each + # DIMM slot + +#ifdef SIZE_ALL + movw %fs, %ax # enable DIMMx on reg. 0x64 and save + # it in FS + movb $0x01, %bl + movb %bh, %cl + shlb %cl, %bl + orb %bl, %al + movw %ax, %fs +no_sdram: + incb %bh + cmpb $0x04, %bh # total 4 DIMM slots supported + jb spd_sizing_start + + movw %fs, %ax + movb $0x64, %ah +#else /* !SIZE_ALL */ +no_sdram: + movw $0x6401, %ax # enable DIMM 0 +#endif /* SIZE_ALL */ + + CALL_SP(write_north_register) # write DRAM status register 0x64 + +#endif + +/* -----------------------------------------------------------------------------------------*/ + + /* Start JEDEC DDR initialization sequence */ +jedec_ddr_init_seq: + movb NO_OP, %bl + CALL_BP(dram_ctrl_cmd) + + movw $ddr_init_table, %si +init_ddr_sdram: + lodsb (%si), %al + testb %al, %al + jz ddr_init_complete + + movb %al, %bl + CALL_BP(dram_ctrl_cmd) + jmp init_ddr_sdram + +ddr_init_complete: + + movw $post_dram_init_table, %si +post_dram_init_start: + lodsw (%si), %ax + testw %ax, %ax + jz post_dram_init_complete + + CALL_SP(write_north_register) + jmp post_dram_init_start + +post_dram_init_complete: + +/* -----------------------------------------------------------------------------------------*/ + +sis735ipl_start: + /* O.K. we have DRAM now, so set up STACK for CALL/RET */ + movw $DOC_STACK_SEG, %ax + movw %ax, %ss + movw $SPL_RAM_SEG, %ax + movw %ax, %es + xorw %sp, %sp # clear %sp + +#ifdef STD_FLASH +#include "rom/std_flash.inc" +#else /* !STD_FLASH */ +#include "unlock_flash.inc" +#if defined(USE_DOC_MIL) || defined(USE_DOC_2000_TSOP) +# include "rom/doc_mil.inc" +#else defined(USE_DOC_MIL_PLUS) +# include "rom/doc_mil_plus.inc" +#endif +#endif /* STD_FLASH */ + +sis735ipl_end: + jmp spl_vector # jump to SPL vector + + +/* -----------------------------------------------------------------------------------------*/ + +write_north_register: + /* Input: AH - register number. AL - register value. + Chnaged: CX, EDX */ + movl $NORTH_BRIDGE_BASE_ADDR, %edx + jmp write_common + +write_lpc_register: + /* Input: AH - register number. AL - register value. + Chnaged: CX, EDX */ + movl $LPC_BRIDGE_BASE_ADDR, %edx + jmp write_common + +write_smbus_register: + /* Input: AH - register number. AL - register value. + Chnaged: CX, EDX */ + movl $SMBUS_HOST_BASE_ADDR, %edx + jmp write_common + +write_common: + movw %ax, %cx # Save %ax to %cx. + + movzbl %ch, %eax # add register address to + addl %edx, %eax # PCI base address + + movw $PCI_COMMAND_PORT, %dx + outl %eax, %dx + + movw $PCI_DATA_PORT, %dx + andb $0x03, %al + addb %al, %dl + movw %cx, %ax + outb %al, %dx + RET_SP # End of write_[pci|smbus]_reg + +/* -----------------------------------------------------------------------------------------*/ +read_north_register: + /* Input: AH - register number. + Output AL - register value. + Chnaged: CX, EDX */ + movl $NORTH_BRIDGE_BASE_ADDR, %edx + +read_common: + movw %ax, %cx # Save %ax to %cx. + + movzbl %ch, %eax # add register address to + addl %edx, %eax # PCI base address + + movw $PCI_COMMAND_PORT, %dx + outl %eax, %dx + + movw $PCI_DATA_PORT, %dx + andb $0x03, %al + addb %al, %dl + inb %dx, %al + + movb %ch, %ah # Resotre register number to %ah + + RET_SP # End of write_[pci|smb] + +write_north_register_or: + /* Input: AH - register number. AL - register mask. + Chnaged: CX, EDX*/ + CALL_SP(read_north_register) # %cl == old %al + orb %cl, %al + CALL_SP(write_north_register) + RET_BP + +/* -----------------------------------------------------------------------------------------*/ + +dram_ctrl_cmd: + /* Input: BL - DRAM COMMAND. + Chnaged: AX, CX, EDX*/ + movb $0x5C, %ah # read 0x5C DRAM Init Control + CALL_SP(read_north_register) + andb $0x07, %al # Clear Command bits + orb %bl, %al # Set DRAM command + CALL_SP(write_north_register) + orb $0x08, %al # Issue DRAM Command + CALL_SP(write_north_register) + RET_BP + +/* -----------------------------------------------------------------------------------------*/ + +read_spd: + /* Input: AH = 05h, AL = byte number of SPD to be read. + Output: BL = The value of specified SPD byte. */ + movb $0x05, %ah # set SMB Command == byte address + CALL_BP(sis_set_smbus) + + movw $0x0312, %ax # Start, R/W byte Data + CALL_BP(sis_set_smbus) + +wait_for_smbus_read: + movb $0x80, %dl # Read SMBus status + inb %dx, %al + + testb $0x02, %al # if device errors + jnz read_spd_fail # then skip read SPD + + testb $0x08, %al # if not complete + jz wait_for_smbus_read # then wait SPD data complete + +read_spd_fail: + movb $0x08, %ah + +sis_get_smbus: + /* Input: AH - register index. + Output: BL - register value. */ + addb %ah, %dl # read SMBus byte 0 + inb %dx, %al + movb %al, %bl # return result in BL + + movw $0x00ff, %ax + CALL_BP(sis_set_smbus) # clear ACPI 80h status + + RET_SP # End of read_spd + +sis_set_smbus: + /* Input: AH - register index. AL - register value. */ + movw $SMB_BASE_ADDR, %dx + addb %ah, %dl + outb %al, %dx + RET_BP # End of sis_set_smbus + +/* -----------------------------------------------------------------------------------------*/ + +sdram_type_bank_1: +# Column Number 8 9 10 11 Row Number + .byte 0b0000, 0b0100, 0b1000, 0xff # 11 + .byte 0xff, 0xff, 0xff, 0xff # 12 + .byte 0b0001, 0b0101, 0b1001, 0xff # 13 + +sdram_type_bank_2: +# Column Number 8 9 10 11 Row Number + .byte 0b1100, 0xff, 0xff, 0xff # 11 + .byte 0b0010, 0b0110, 0b1010, 0b1110 # 12 + .byte 0b0011, 0b0111, 0b1011, 0b1111 # 13 +# FixMe: Bank 2 x Column 12 x Row 13 == 1GB + +/* -----------------------------------------------------------------------------------------*/ + +pre_dram_sizing_table: +# High Byte -> Register Low Byte -> Value + /* DRAM Control */ + .word 0x5929 # CAS Latency = 2.5T + .word 0x5c12 # MD/DQS Input Enable for DDR + .word 0x5dc0 # Refresh Cycle Disabled + + /* ACPI Control */ + .word 0x6801 # ACPI Enable. + .word 0x6950 # Store ACPI Base Address. + + /* IO Buffer */ + .word 0x9910 # DDR IO Input Mode ==> Differential + .word 0x9ab8 # Enable DQS signal delay + + .word 0x0000 /* Null, End of table */ + +post_dram_init_table: +# High Byte -> Register Low Byte -> Value + .word 0x0407 # Enable IO/MEM Space, BM DMA + .word 0x0d20 + + /* DRAM Control */ + .word 0x5dc1 # Refresh Cycle Enabled + + .word 0x0000 /* Null, End of table */ + +smbus_init_table: +# High Byte -> Register Low Byte -> Value + .word 0x0401 # enable IO space + .word 0x2080 # SMBus Base address = + .word 0x2150 # 0x5080 + .word 0x4001 # enable SMBus Host Controller + .word 0x0000 /* Null, End of table */ + +ddr_init_table: + .byte PALL # Percharge All + .byte DLL_EN_N # DLL Enable Normal + .byte DLL_RESET # DLL Reset + .byte PALL # Precharge All + .byte REF # Refresh + .byte REF # Refresh + .byte MRS # Mode Register Set + .byte 0x0000 /* Null, End of table */ + +/* -----------------------------------------------------------------------------------------*/ +#ifdef STD_FLASH + .org 0xfff0 +reset_vector: + .byte 0xea # jmp to f000:fc00, where IPL + .word 0xfc00, 0xf000 # starts in Standard Flash +#else /* !STD_FLASH i.e. DoC Mil */ +#if defined(USE_DOC_MIL) + .org 0x1f0 +#elif defined(USE_DOC_2000_TSOP) || defined(USE_DOC_MIL_PLUS) + .org 0x3f0 +#endif +reset_vector: + .byte 0xea # jmp to fc00:0000, where IPL + .word 0x0000, DOC_WIN_SEG # starts in DoC +#endif /* STD_FLASH */ + +spl_vector: + .byte 0xea # jmp to 8000:0000, where SPL + .word 0x0000, SPL_RAM_SEG # (LinuxBIOS) starts in RAM + +/* -----------------------------------------------------------------------------------------*/ + +sis950_init_table: + .byte 0x87, 0x01, 0x55, 0x55, 0x24 + +end: + hlt diff --git a/src/northsouthbridge/sis/735/ipl.h b/src/northsouthbridge/sis/735/ipl.h new file mode 100644 index 0000000000..57c8d66a84 --- /dev/null +++ b/src/northsouthbridge/sis/735/ipl.h @@ -0,0 +1,67 @@ +#define PCI_COMMAND_PORT 0xcf8 +#define PCI_DATA_PORT 0xcfc + +#define NORTH_BRIDGE_BASE_ADDR 0x80000000 /* Bus 0, Device 0, Function 0 */ +#define LPC_BRIDGE_BASE_ADDR 0x80001000 /* Bus 0, Device 2, Function 0 */ +#define SMBUS_HOST_BASE_ADDR 0x80001100 /* Bus 0, Device 2, Function 1 */ + +#define ACPI_BASE_ADDR 0x5000 +#define SMB_BASE_ADDR 0x5080 + +/* DDR Initialization Register and Command */ +#define DRAM_INIT_REG 0x5c +#define DQS_ENABLE 0x02 +#define DDR_CMD_ISSUE 0x08 +#define NO_OP 0x00 +#define PALL 0x10 +#define MRS 0x20 +#define REF 0x30 +#define DLL_EN_N 0x40 +#define DLL_EN_W 0x50 +#define DLL_RESET 0x60 +#define DLL_DISABLE 0x70 + +#define DDR_CMD DDR_CMD_ISSUE | DQS_ENABLE +#define DDR_CMD_PALL (DRAM_INIT_REG << 8 | PALL | DDR_CMD) +#define DDR_CMD_DLL_EN_N (DRAM_INIT_REG << 8 | DLL_EN_N | DDR_CMD) +#define DDR_CMD_DLL_RESET (DRAM_INIT_REG << 8 | DLL_RESET | DDR_CMD) +#define DDR_CMD_REF (DRAM_INIT_REG << 8 | REF | DDR_CMD) +#define DDR_CMD_MRS (DRAM_INIT_REG << 8 | MRS | DDR_CMD) + +#define ENABLE_FRESH_CYCLE 0x5d01 + +#define DOC_WIN_SEG 0xfe00 +#define DOC_STACK_SEG 0x0400 +#define SPL_RAM_SEG 0x8000 + +#if defined(USE_DOC_2000_TSOP) +#define DOC_SPL_START_PAGE 4 /* 0-3 for IPL (each of 1KB size) */ +#else /* defined (USE_DOC_MIL) */ +#define DOC_SPL_START_PAGE 2 /* 0,1 for IPL (each of 512B size) */ +#endif + +#define DOC_SPL_SIZE_IN_PAGE 128 - DOC_SPL_START_PAGE /* 1 page = 512 bytes, total 63kB */ + +/* Pseudo Call and Return macros */ +#define RET_LABEL(label) \ + jmp label##_done + +#define CALL_LABEL(label) \ + jmp label ;\ +label##_done: + +#define CALL_SP(func) \ + lea 0f, %sp ; \ + jmp func ; \ +0: + +#define RET_SP \ + jmp *%sp + +#define CALL_BP(func) \ + lea 0f, %bp ; \ + jmp func ; \ +0: + +#define RET_BP \ + jmp *%bp diff --git a/src/northsouthbridge/sis/735/northbridge.c b/src/northsouthbridge/sis/735/northbridge.c new file mode 100644 index 0000000000..c4f147ff1c --- /dev/null +++ b/src/northsouthbridge/sis/735/northbridge.c @@ -0,0 +1,109 @@ +/* + * northbridge.c: SiS 735 Northbridge Initialization + * + * Copyright 2002 International Business Machines + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 735 Programing Guide + * + */ + +#include +#include +#include +#include +#include + +/* these functions query the hardware to figure out how much ram is in + * the machine. They then place that information in the parameter block. + * This is kind of schizophrenic, but we do it this way because the + * functions that actually set the registers are kind of hairy, and + * we're not sure they can carry the full burden of also passing on + * the size information to the rest of the bootstrap. Besides, querying + * hardware for ram sizes is trivial. + */ + +/* table for calculate the DRAM size, the unit is Mega Bytes */ +const static int ramsizes[16] = +{ + 8, 32, 32, 64, 16, 64, 64, 128, + 32, 128, 128, 256, 16, 1024, 256, 512 +}; +#define SIS735_BANKENABLE 0x64 +#define SIS735_BANK0 0x60 +#define SIS735_BANK1 0x61 +#define SIS735_BANK2 0x62 +#define SIS735_BANK3 0x63 +unsigned +long sizeram() +{ + struct pci_dev *pcidev; + unsigned int dimm_slot, dimm_reg, sides; + unsigned long total_size; + u8 dram_status, dimm_status; + + if ((pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, NULL)) == NULL) + return 0; + + pci_read_config_byte(pcidev, SIS735_BANKENABLE, &dram_status); + dimm_status = dram_status & 0xF; + + for (dimm_slot = 0, total_size = 0, dimm_reg = SIS735_BANK0; + dimm_reg <= SIS735_BANK3; dimm_slot++, dimm_reg++) { + u8 regval; + if ((dimm_status & (1 << dimm_slot)) == 0) + /* this DIMM slot does not have SDRAM installed */ + continue; + + pci_read_config_byte(pcidev, dimm_reg, ®val); + + /* is this DIMM single or double sided ?? */ + if (regval & 0x20) + sides = 2; + else + sides = 1; + + /* low-order 4 bits are a ram size */ + total_size += (ramsizes[regval & 0xf] * sides); + } + + /* return the memory size in KB */ + total_size *= 1024; + return total_size; +} + +#ifdef HAVE_FRAMEBUFFER +void framebuffer_on() +{ + unsigned long devfn; + u16 command; + + devfn = PCI_DEVFN(2, 0); + + /* Enable VGA Palette Snoop */ + pcibios_read_config_word(0, devfn, 0x04, &command); + command |= 0x20; + pcibios_write_config_word(0, devfn, 0x04, command); + + /* enable legacy VGA IO (0x3B0 - 0x3BB, 0x3C0 - 0x3DF) and MEM (0xA0000 - 0xBFFFF), + needed for XFree86 3.3.6 */ + pcibios_read_config_word(0, devfn, 0x3e, &command); + command |= 0x08; + pcibios_write_config_word(0, devfn, 0x3e, command); +} +#endif /* HAVE_FRAMEBUFFER */ diff --git a/src/northsouthbridge/sis/735/raminit.inc b/src/northsouthbridge/sis/735/raminit.inc new file mode 100644 index 0000000000..3fa51f8090 --- /dev/null +++ b/src/northsouthbridge/sis/735/raminit.inc @@ -0,0 +1,67 @@ +/* + * raminit.inc: Setting registers to their recommended values for SiS 735. + * Since we have inited the DRAM in IPL it is not neceressary + * to do "raminit" here any more. + * + * + * Copyright 2000 Silicon Integrated Systems Corporation + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 735 Programming Guide, Rev. 1.0, Apr. 16, 2001 + * + * $Id$ + */ + +#define PCI_COMMAND_PORT 0xcf8 +#define PCI_DATA_PORT 0xcfc + +#define NORTH_BRIDGE_BASE_ADDR 0x80000000 +#define LPC_BRIDGE_BASE_ADDR 0x80000800 + +register_setting_start: + movl $northbridge_init_table, %esi + movl $(northbridge_init_table_end - northbridge_init_table), %ecx + shrl $0x01, %ecx + +init_northbridge: + lodsw (%esi), %ax # load the register address/value to %ax + +write_northbridge_register: + /* Input: AH - register number. AL - register value. */ + movl $NORTH_BRIDGE_BASE_ADDR, %edx + + movl %eax, %ebx # Save %eax to %ebx. + + movzbl %bh, %eax # add register address to + addl %edx, %eax # PCI base address + + movw $PCI_COMMAND_PORT, %dx + outl %eax, %dx + + movw $PCI_DATA_PORT, %dx + andb $0x03, %al + addb %al, %dl + movb %bl, %al + outb %al, %dx + loopnz init_northbridge + + jmp register_setting_end + +#include "735_regs.inc" + +register_setting_end: diff --git a/src/northsouthbridge/sis/735/southbridge.c b/src/northsouthbridge/sis/735/southbridge.c new file mode 100644 index 0000000000..c597b3baf0 --- /dev/null +++ b/src/northsouthbridge/sis/735/southbridge.c @@ -0,0 +1,299 @@ +/* + * southbridge.c: Southbridge Initialization For SiS 735 + * + * Copyright 2002 International Business Machines + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * 1. SiS 735 Programing Guide + */ + +#ifndef lint +static char rcsid[] = +"$Id$"; +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#define BYTE sizeof(u8) +#define WORD sizeof(u16) +#define DBLE sizeof(u32) +#define IDE_REG_EXTENDED_OFFSET (0x200u) +#define IDE_REG_SECTOR_COUNT(base) ((base) + 2u) +#define IDE_REG_CONTROL(base) ((base) + IDE_REG_EXTENDED_OFFSET + 6u) +#define IDE_BASE1 (0x1F0u) /* primary controller */ +#define ASIZE(x) (sizeof(x)/sizeof((x)[0])) + +typedef struct { + u8 size; + u8 regno; + u32 andval; + u32 orval; +} initreg_t; + +static const initreg_t ide_init[] = { + /* + * BUS(0), DEVICE(0), FUNCTION(1): IDE Interface. Bridge + */ + /* SIZE REG AND-MASK OR-MASK */ + { WORD, 0x04, 0x00, 0x0007 }, /* Command Register. sets mem+ */ + { WORD, 0x06, 0x00, 0x3000 }, /* Status reg, clear aborts. */ + { WORD, 0x09, 0x0A, 0x00 }, /* Programming interface = Compatible mode. */ + { BYTE, 0x0D, 0x00, 0x80 }, /* Latency Timer */ + /* We let the pci enumerator assign these. */ + // { DBLE, 0x10, 0x0, 0x1F1 }, /* Primary channel base addr. */ + // { DBLE, 0x14, 0x0, 0x3F5 }, /* Primary channel control base addr. */ + // { DBLE, 0x18, 0x0, 0x171 }, /* Secondary channel base addr. */ + // { DBLE, 0x1C, 0x0, 0x375 }, /* Secondary channel control base addr. */ + // { DBLE, 0x20, 0x0, 0x4001 }, /* Control register base addr. */ + { WORD, 0x2C, 0x00, 0x1039 }, /* Subsystem vendor ID. */ + { WORD, 0x2E, 0x00, 0x5513 }, /* Subsystem ID. */ + { BYTE, 0x3c, 0x00, 0x0e }, /* reserved don't do this, sets irq 14 */ + { BYTE, 0x40, 0x00, 0x44 }, /* Primary master data active/recovery time. PIO Mode 2 */ + { BYTE, 0x41, 0x00, 0x85 }, /* Primary master UDMA cycle time. UDMA Mode 2 */ + { BYTE, 0x42, 0x00, 0x00 }, /* Primary slave data recovery time. */ + { BYTE, 0x43, 0x00, 0x00 }, /* Primary slave data active time. */ + { BYTE, 0x44, 0x00, 0x00 }, /* Secondary master data recovery time. */ + { BYTE, 0x45, 0x00, 0x00 }, /* Secondary master data active time. */ + { BYTE, 0x46, 0x00, 0x00 }, /* Secondary slave data recovery time. */ + { BYTE, 0x47, 0x00, 0x00 }, /* Secondary slave data active time. */ + { BYTE, 0x48, 0x00, 0x08 }, /* Read/Write FIFO Threshold = 1/4 */ + { BYTE, 0x4A, 0x40, 0xe6 }, /* Enable Bus Master, Fast postwrite, IDE 0 */ + { BYTE, 0x4B, 0x00, 0x11 }, /* Enable Postwrite and Prefech for IDE0, Master */ + { WORD, 0x4C, 0x00, 0x0200 }, /* Prefetch count of primary. */ + { WORD, 0x4E, 0x00, 0x0200 }, /* Prefetch count of secondary. */ + { BYTE, 0x52, 0xFF, 0x14 } /* Miscelaneous control (Only Doc). */ +}; + +void ide_fixup(void) +{ + + struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, + (void *) NULL); + int i; + u8 val8; + u16 val16; + u32 val32; + + int initlen = ASIZE(ide_init); + const initreg_t * inittab = ide_init; + + printk_info ("Entering the initregs process\n"); + + for (i = 0; i < initlen; ++i) { + u16 regno = inittab[i].regno; + switch (inittab[i].size) { + case BYTE: + pci_read_config_byte(dev, regno, &val8); + val8 = (val8 & inittab[i].andval) | inittab[i].orval; + pci_write_config_byte(dev, regno, val8); + break; + case WORD: + pci_read_config_word(dev, regno, &val16); + val16 = (val16 & inittab[i].andval) | inittab[i].orval; + pci_write_config_word(dev, regno, val16); + break; + case DBLE: + pci_read_config_dword(dev, regno, &val32); + val32 = (val32 & inittab[i].andval) | inittab[i].orval; + break; + + default: + outb_p(0xEE,0x80); + while(1); + break; + } + } +} + +void keyboard_on() +{ + u8 regval; + struct pci_dev *pcidev; + void pc_keyboard_init(void); + + /* turn on sis735 keyboard/mouse controller */ + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, (void *)NULL); + if (pcidev != NULL) { + /* Register 0x47, Keyboard Controller */ + pci_read_config_byte(pcidev, 0x47, ®val); + /* enable both integrated keyboard and PS/2 mouse controller */ + regval |= 0x0c; + pci_write_config_byte(pcidev, 0x47, regval); + } + pc_keyboard_init(); +} + +void nvram_on() +{ + struct pci_dev *pcidev; + u8 tmp; + + /* turn on sis735 nvram. */ + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, (void *)NULL); + + if (pcidev != NULL) { + printk_info("Enabling nvram\n"); + /* Enable FFF80000 to FFFFFFFF decode. You have to also enable + PCI Posted write for devices on sourthbridge */ + pci_read_config_byte(pcidev, 0x40, &tmp); + tmp |= 0x3; + pci_write_config_byte(pcidev, 0x40, tmp); + } + +#if !defined(STD_FLASH) + /* turn off nvram shadow in 0xc0000 ~ 0xfffff, i.e. accessing segment C - F + is actually to the DRAM not NVRAM. For 512KB NVRAM case, this one should be + disabled */ + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, (void *)NULL); + if (pcidev != NULL) { + /* read cycle goes to System Memory */ + pci_write_config_word(pcidev, 0x70, 0x1fff); + /* write cycle goest to System Memory */ + pci_write_config_word(pcidev, 0x72, 0x1fff); + printk_debug("Shadow memory disabled in SiS 735\n"); + + } +#endif +} + +/* serial_irq_fixup: Enable Serial Interrupt. Serial interrupt is the IRQ line from SiS 950 + * LPC to Host Controller. Serial IRQ is neceressary for devices on SiS 950 + * ie.e floppy, COM, LPT etc + */ +static void +serial_irq_fixedup(void) +{ + struct pci_dev *pcidev; + + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, (void *)NULL); + if (pcidev != NULL) { + /* enable Serial Interrupt (SIRQ) */ + pci_write_config_byte(pcidev, 0x69, 0x80); + pci_write_config_byte(pcidev, 0x67, 0x10); + } +} + +/* timer0_fixup: Fix up the Timer 0 of 8254 Programmable Timer + * + * The timer 0 is used to generate the 18.2 Hz, IRQ 0 timer event and used by system + * to update date/time. + * + * FixME: Should be program timer 1 for DRAM refresh too ?? + */ +static void +timer0_fixup(void) +{ + /* select Timer 0, 16 Bit Access, Mode 3, Binary */ + outb_p(0x43, 0x36); + + /* Load LSB, 0x00 */ + outb_p(0x40, 0x00); + + /* Load MSB, 0x00 */ + outb_p(0x40, 0x00); +} + +/* rtc_fixup: Fix up the Real Time Clock + * + * The Real Time Clock updates the day/time information in the CMOS RAM every second. + * The clock diveder has to be programmed correctly or the RTC will update the CMOS + * in incorrect time interval (i.e. more or less then 1Sec in "wall clock"). + * + * FixME: Where does the CMOS stroe Y2K information and how does Linux handle it ?? + */ +static void +rtc_fixup(void) +{ + volatile u8 dummy; + u8 regval; + struct pci_dev *isa_bridge; + + isa_bridge = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, + (void *)NULL); + if (isa_bridge != NULL) { + /* Register 0x48, Enable internal RTC */ + pci_read_config_byte(isa_bridge, 0x48, ®val); + pci_write_config_byte(isa_bridge, 0x48, regval | 0x10); + } + + /* Select Normal Colok Divider, 978 us interrupt */ + outb_p(0x0A, 0x70); + outb_p(0x26, 0x71); + + /* Select 24 HR time */ + outb_p(0x0B, 0x70); + outb_p(0x02, 0x71); + + /* Clear Checksum Error */ + outb_p(0x0D, 0x70); + dummy = inb_p(0x71); +} + +static void +acpi_fixup(void) +{ + struct pci_dev *pcidev; + + pcidev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, (void *)NULL); + if (pcidev != NULL) { + unsigned char val; + unsigned short acpibase = 0xc000, temp; + + // the following is to turn off software watchdogs. + // we co-op the address space from c000-cfff here. Temporarily. + // Later, we need a better way to do this. + // But since Linux doesn't even understand this yet, no issue. + // Set a base address for ACPI of 0xc000 + pci_write_config_word(pcidev, 0x74, acpibase); + + // now enable acpi + pci_read_config_byte(pcidev, 0x40, &val); + val |= 0x80; + pci_write_config_byte(pcidev, 0x40, val); + + /* Disable Auto-Reset */ + val = inb(acpibase + 0x56); + outw(val | 0x40, acpibase + 0x56); + /* Disable Software Watchdog */ + outb(0, acpibase + 0x4b); + } else { + printk_emerg("Can't find south bridge!\n"); + } + +} + +// simple fixup (which we hope can leave soon) for the sis southbridge part +void +final_southbridge_fixup() +{ + timer0_fixup(); + rtc_fixup(); + nvram_on(); + acpi_fixup(); + ide_fixup(); + + printk_debug("Southbridge fixup done for SIS 735\n"); +} + diff --git a/src/northsouthbridge/sis/735/unlock_flash.inc b/src/northsouthbridge/sis/735/unlock_flash.inc new file mode 100644 index 0000000000..e079e5b4e2 --- /dev/null +++ b/src/northsouthbridge/sis/735/unlock_flash.inc @@ -0,0 +1,7 @@ + movw $sis950_init_table, %si # unlock SiS 950 LPC + movw $0x05, %cx # select Clock Selection + movw $0x2e, %dx # and Flash ROM I/F + rep + outsb + movb $0xfd, %al # enable write, CLKIN = 24 MHZ + outb %al, $0x2f