diff options
author | Richard Smith <smithbone@gmail.com> | 2006-07-24 04:25:47 +0000 |
---|---|---|
committer | Richard Smith <smithbone@gmail.com> | 2006-07-24 04:25:47 +0000 |
commit | cb8eab482ff09ec256456312ef2d6e7710123551 (patch) | |
tree | 7bc1297911194e564b967efba4a03c4dde5f7a13 /src | |
parent | 4788effb045ae1f71d89c78a0b16a93d5ba79e89 (diff) | |
download | coreboot-cb8eab482ff09ec256456312ef2d6e7710123551.tar.xz |
add framework for i440bx chipset
add support for NSC pc87351 SuperIO
add Bitworks/IMS manboard config
This is a very basic framework for the i440bx chipset and the
Bitworks IMS board that uses it. Most things are
structure only.
Known issues:
- SMbus reads to the RAM SPD come back
all zero.
- dump_spd_registers() is commented out since it breaks with
the default setting of generic_dump_spd.c where it wants
2 memory controllers.
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2347 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
28 files changed, 1782 insertions, 0 deletions
diff --git a/src/cpu/intel/socket_PGA370/Config.lb b/src/cpu/intel/socket_PGA370/Config.lb new file mode 100644 index 0000000000..8db263b5a0 --- /dev/null +++ b/src/cpu/intel/socket_PGA370/Config.lb @@ -0,0 +1,3 @@ +config chip.h +object socket_PGA370.o +dir /cpu/intel/model_6xx diff --git a/src/cpu/intel/socket_PGA370/chip.h b/src/cpu/intel/socket_PGA370/chip.h new file mode 100644 index 0000000000..469b662dfb --- /dev/null +++ b/src/cpu/intel/socket_PGA370/chip.h @@ -0,0 +1,4 @@ +extern struct chip_operations cpu_intel_socket_PGA370_ops; + +struct cpu_intel_socket_PGA370_config { +}; diff --git a/src/cpu/intel/socket_PGA370/socket_PGA370.c b/src/cpu/intel/socket_PGA370/socket_PGA370.c new file mode 100644 index 0000000000..690e69d0a9 --- /dev/null +++ b/src/cpu/intel/socket_PGA370/socket_PGA370.c @@ -0,0 +1,7 @@ +#include <device/device.h> +#include "chip.h" + + +struct chip_operations cpu_intel_socket_PGA370_ops = { + CHIP_NAME("socket PGA370") +}; diff --git a/src/mainboard/bitworks/ims/Config.lb b/src/mainboard/bitworks/ims/Config.lb new file mode 100644 index 0000000000..357a1013ff --- /dev/null +++ b/src/mainboard/bitworks/ims/Config.lb @@ -0,0 +1,136 @@ +## +## Compute the location and size of where this firmware image +## (linuxBIOS plus bootloader) will live in the boot rom chip. +## +if USE_FALLBACK_IMAGE + default ROM_SECTION_SIZE = FALLBACK_SIZE + default ROM_SECTION_OFFSET = ( ROM_SIZE - FALLBACK_SIZE ) +else + default ROM_SECTION_SIZE = ( ROM_SIZE - FALLBACK_SIZE ) + default ROM_SECTION_OFFSET = 0 +end + +## +## Compute the start location and size size of +## The linuxBIOS bootloader. +## +default CONFIG_ROM_STREAM_START = (0xffffffff - ROM_SIZE + ROM_SECTION_OFFSET + 1) +default PAYLOAD_SIZE = ( ROM_SECTION_SIZE - ROM_IMAGE_SIZE ) + +## +## Compute where this copy of linuxBIOS will start in the boot rom +## +default _ROMBASE = ( CONFIG_ROM_STREAM_START + PAYLOAD_SIZE ) + +## +## Compute a range of ROM that can cached to speed up linuxBIOS, +## execution speed. +## +## XIP_ROM_SIZE must be a power of 2. +## XIP_ROM_BASE must be a multiple of XIP_ROM_SIZE +## +default XIP_ROM_SIZE=65536 +default XIP_ROM_BASE = ( _ROMBASE + ROM_IMAGE_SIZE - XIP_ROM_SIZE ) + +## +## Set all of the defaults for an x86 architecture +## + +arch i386 end + +## +## Build the objects we have code for in this directory. +## + +driver mainboard.o + +#if HAVE_PIRQ_TABLE object irq_tables.o end +#object reset.o + +## +## Romcc output +## +makerule ./failover.E + depends "$(MAINBOARD)/failover.c ./romcc" + action "./romcc -E -O --label-prefix=failover -I$(TOP)/src -I. $(CPPFLAGS) $(MAINBOARD)/failover.c -o $@" +end + +makerule ./failover.inc + depends "$(MAINBOARD)/failover.c ./romcc" + action "./romcc -O --label-prefix=failover -I$(TOP)/src -I. $(CPPFLAGS) $(MAINBOARD)/failover.c -o $@" +end + +makerule ./auto.E + depends "$(MAINBOARD)/auto.c option_table.h ./romcc" + action "./romcc -E -mcpu=i386 -O -I$(TOP)/src -I. $(CPPFLAGS) $(MAINBOARD)/auto.c -o $@" +end +makerule ./auto.inc + depends "$(MAINBOARD)/auto.c option_table.h ./romcc" + action "./romcc -mcpu=i386 -O -I$(TOP)/src -I. $(CPPFLAGS) $(MAINBOARD)/auto.c -o $@" +end + +## +## Build our 16 bit and 32 bit linuxBIOS entry code +## +mainboardinit cpu/x86/16bit/entry16.inc +mainboardinit cpu/x86/32bit/entry32.inc +ldscript /cpu/x86/16bit/entry16.lds +ldscript /cpu/x86/32bit/entry32.lds + +## +## Build our reset vector (This is where linuxBIOS is entered) +## +if USE_FALLBACK_IMAGE + mainboardinit cpu/x86/16bit/reset16.inc + ldscript /cpu/x86/16bit/reset16.lds +else + mainboardinit cpu/x86/32bit/reset32.inc + ldscript /cpu/x86/32bit/reset32.lds +end + +### Should this be in the northbridge code? +mainboardinit arch/i386/lib/cpu_reset.inc + +## +## Include an id string (For safe flashing) +## +mainboardinit arch/i386/lib/id.inc +ldscript /arch/i386/lib/id.lds + +### +### This is the early phase of linuxBIOS startup +### Things are delicate and we test to see if we should +### failover to another image. +### +if USE_FALLBACK_IMAGE + ldscript /arch/i386/lib/failover.lds + mainboardinit ./failover.inc +end + +### +### O.k. We aren't just an intermediary anymore! +### + +## +## Setup RAM +## +mainboardinit cpu/x86/fpu/enable_fpu.inc +mainboardinit cpu/x86/mmx/enable_mmx.inc +mainboardinit ./auto.inc +mainboardinit cpu/x86/mmx/disable_mmx.inc + +## +## Include the secondary Configuration files +## +dir /pc80 +config chip.h + +chip northbridge/intel/i440bx + device pci_domain 0 on + end + + chip cpu/intel/socket_PGA370 + end + +end + diff --git a/src/mainboard/bitworks/ims/Options.lb b/src/mainboard/bitworks/ims/Options.lb new file mode 100644 index 0000000000..a67e1495cb --- /dev/null +++ b/src/mainboard/bitworks/ims/Options.lb @@ -0,0 +1,156 @@ +uses HAVE_MP_TABLE +uses HAVE_PIRQ_TABLE +uses USE_FALLBACK_IMAGE +uses HAVE_FALLBACK_BOOT +uses HAVE_HARD_RESET +uses HAVE_OPTION_TABLE +uses USE_OPTION_TABLE +uses CONFIG_ROM_STREAM +uses IRQ_SLOT_COUNT +uses MAINBOARD +uses MAINBOARD_VENDOR +uses MAINBOARD_PART_NUMBER +uses LINUXBIOS_EXTRA_VERSION +uses ARCH +uses FALLBACK_SIZE +uses STACK_SIZE +uses HEAP_SIZE +uses ROM_SIZE +uses ROM_SECTION_SIZE +uses ROM_IMAGE_SIZE +uses ROM_SECTION_SIZE +uses ROM_SECTION_OFFSET +uses CONFIG_ROM_STREAM_START +uses PAYLOAD_SIZE +uses _ROMBASE +uses _RAMBASE +uses XIP_ROM_SIZE +uses XIP_ROM_BASE +uses HAVE_MP_TABLE +uses CROSS_COMPILE +uses CC +uses HOSTCC +uses OBJCOPY +uses DEFAULT_CONSOLE_LOGLEVEL +uses MAXIMUM_CONSOLE_LOGLEVEL +uses CONFIG_CONSOLE_SERIAL8250 +uses TTYS0_BAUD +uses TTYS0_BASE +uses TTYS0_LCS +uses CONFIG_UDELAY_TSC + +## ROM_SIZE is the size of boot ROM that this board will use. +default ROM_SIZE = 512*1024 + +### +### Build options +### + +## +## Build code for the fallback boot +## +default HAVE_FALLBACK_BOOT=1 + +## +## no MP table +## +default HAVE_MP_TABLE=0 + +## +## Build code to reset the motherboard from linuxBIOS +## +default HAVE_HARD_RESET=0 + +## +## Build code to export a programmable irq routing table +## +default HAVE_PIRQ_TABLE=0 +default IRQ_SLOT_COUNT=4 +#object irq_tables.o + +## +## Build code to export a CMOS option table +## +default HAVE_OPTION_TABLE=0 + +### +### LinuxBIOS layout values +### + +## ROM_IMAGE_SIZE is the amount of space to allow linuxBIOS to occupy. +default ROM_IMAGE_SIZE = 65536 +default FALLBACK_SIZE = 131072 + +## +## Use a small 8K stack +## +default STACK_SIZE=0x2000 + +## +## Use a small 16K heap +## +default HEAP_SIZE=0x4000 + +## +## Only use the option table in a normal image +## +#default USE_OPTION_TABLE = !USE_FALLBACK_IMAGE +default USE_OPTION_TABLE = 0 + +default _RAMBASE = 0x00004000 + +default CONFIG_ROM_STREAM = 1 + +## +## The default compiler +## +default CROSS_COMPILE="" +default CC="$(CROSS_COMPILE)gcc -m32" +default HOSTCC="gcc" + +## +## The Serial Console +## + +# To Enable the Serial Console +default CONFIG_CONSOLE_SERIAL8250=1 + +## Select the serial console baud rate +default TTYS0_BAUD=115200 +#default TTYS0_BAUD=57600 +#default TTYS0_BAUD=38400 +#default TTYS0_BAUD=19200 +#default TTYS0_BAUD=9600 +#default TTYS0_BAUD=4800 +#default TTYS0_BAUD=2400 +#default TTYS0_BAUD=1200 + +# Select the serial console base port +default TTYS0_BASE=0x3f8 + +# Select the serial protocol +# This defaults to 8 data bits, 1 stop bit, and no parity +default TTYS0_LCS=0x3 + +## +### Select the linuxBIOS loglevel +## +## EMERG 1 system is unusable +## ALERT 2 action must be taken immediately +## CRIT 3 critical conditions +## ERR 4 error conditions +## WARNING 5 warning conditions +## NOTICE 6 normal but significant condition +## INFO 7 informational +## DEBUG 8 debug-level messages +## SPEW 9 Way too many details + +## Request this level of debugging output +default DEFAULT_CONSOLE_LOGLEVEL=9 +## At a maximum only compile in this level of debugging +default MAXIMUM_CONSOLE_LOGLEVEL=9 + +default CONFIG_UDELAY_TSC=1 + +end + diff --git a/src/mainboard/bitworks/ims/auto.c b/src/mainboard/bitworks/ims/auto.c new file mode 100644 index 0000000000..c841d61044 --- /dev/null +++ b/src/mainboard/bitworks/ims/auto.c @@ -0,0 +1,154 @@ +#define ASSEMBLY 1 + +#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 "pc80/serial.c" +#include "arch/i386/lib/console.c" +#include "ram/ramtest.c" +#include "southbridge/intel/i440bx/i440bx_early_smbus.c" +#include "superio/NSC/pc87351/pc87351_early_serial.c" +#include "northbridge/intel/i440bx/raminit.h" +#include "cpu/x86/mtrr/earlymtrr.c" +#include "cpu/x86/bist.h" + +#define SERIAL_DEV PNP_DEV(0x2e, PC87351_SP1) + +/* + */ +void udelay(int usecs) +{ + int i; + for(i = 0; i < usecs; i++) + outb(i&0xff, 0x80); +} + +#include "debug.c" +#include "lib/delay.c" + + +static void memreset_setup(void) +{ +} + +/* + static void memreset(int controllers, const struct mem_controller *ctrl) + { + } +*/ + + +static void enable_mainboard_devices(void) +{ + device_t dev; + /* dev 0 for southbridge */ + + dev = pci_locate_device(PCI_ID(0x1106,0x8231), 0); + + if (dev == PCI_DEV_INVALID) { + die("Southbridge not found!!!\n"); + } + pci_write_config8(dev, 0x50, 7); + pci_write_config8(dev, 0x51, 0xff); +#if 0 + // This early setup switches IDE into compatibility mode before PCI gets + // // a chance to assign I/Os + // movl $CONFIG_ADDR(0, 0x89, 0x42), %eax + // // movb $0x09, %dl + // movb $0x00, %dl + // PCI_WRITE_CONFIG_BYTE + // +#endif + /* we do this here as in V2, we can not yet do raw operations + * to pci! + */ + dev += 0x100; /* ICKY */ + + pci_write_config8(dev, 0x42, 0); +} + +static void enable_shadow_ram(void) +{ + device_t dev = 0; /* no need to look up 0:0.0 */ + unsigned char shadowreg; + /* dev 0 for southbridge */ + shadowreg = pci_read_config8(dev, 0x63); + /* 0xf0000-0xfffff */ + shadowreg |= 0x30; + pci_write_config8(dev, 0x63, shadowreg); +} + +static inline int spd_read_byte(unsigned device, unsigned address) +{ + unsigned char c; + c = smbus_read_byte(device, address); + return c; +} + + +#include "northbridge/intel/i440bx/raminit.c" +#include "sdram/generic_sdram.c" +//#include "sdram/generic_dump_spd.c" + +static void main(unsigned long bist) +{ + static const struct mem_controller cpu[] = { + { + .channel0 = { + (0xa << 3) | 0, + (0xa << 3) | 1, + (0xa << 3) | 2, (0xa << 3) | 3, + }, + } + }; + unsigned long x; + + if (bist == 0) { + early_mtrr_init(); + } + pc87351_enable_serial(SERIAL_DEV, TTYS0_BASE); + uart_init(); + console_init(); + + /* Halt if there was a built in self test failure */ + report_bist_failure(bist); + + enable_smbus(); +// dump_spd_registers(&cpu[0]); + +#if 0 + enable_shadow_ram(); + /* + memreset_setup(); + this is way more generic than we need. + sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu); + */ + sdram_set_registers((const struct mem_controller *) 0); + sdram_set_spd_registers((const struct mem_controller *) 0); + sdram_enable(0, (const struct mem_controller *) 0); +#endif + + /* Check all of memory */ +#if 0 + ram_check(0x00000000, msr.lo); +#endif +#if 0 + static const struct { + unsigned long lo, hi; + } check_addrs[] = { + /* Check 16MB of memory @ 0*/ + { 0x00000000, 0x01000000 }, +#if TOTAL_CPUS > 1 + /* Check 16MB of memory @ 2GB */ + { 0x80000000, 0x81000000 }, +#endif + }; + int i; + for(i = 0; i < sizeof(check_addrs)/sizeof(check_addrs[0]); i++) { + ram_check(check_addrs[i].lo, check_addrs[i].hi); + } +#endif +} diff --git a/src/mainboard/bitworks/ims/chip.h b/src/mainboard/bitworks/ims/chip.h new file mode 100644 index 0000000000..d0fe923429 --- /dev/null +++ b/src/mainboard/bitworks/ims/chip.h @@ -0,0 +1,5 @@ +extern struct chip_operations mainboard_bitworks_ims_ops; + +struct mainboard_bitworks_ims_config { + int nothing; +}; diff --git a/src/mainboard/bitworks/ims/cmos.layout b/src/mainboard/bitworks/ims/cmos.layout new file mode 100644 index 0000000000..5ba4c032c1 --- /dev/null +++ b/src/mainboard/bitworks/ims/cmos.layout @@ -0,0 +1,74 @@ +entries + +#start-bit length config config-ID name +#0 8 r 0 seconds +#8 8 r 0 alarm_seconds +#16 8 r 0 minutes +#24 8 r 0 alarm_minutes +#32 8 r 0 hours +#40 8 r 0 alarm_hours +#48 8 r 0 day_of_week +#56 8 r 0 day_of_month +#64 8 r 0 month +#72 8 r 0 year +#80 4 r 0 rate_select +#84 3 r 0 REF_Clock +#87 1 r 0 UIP +#88 1 r 0 auto_switch_DST +#89 1 r 0 24_hour_mode +#90 1 r 0 binary_values_enable +#91 1 r 0 square-wave_out_enable +#92 1 r 0 update_finished_enable +#93 1 r 0 alarm_interrupt_enable +#94 1 r 0 periodic_interrupt_enable +#95 1 r 0 disable_clock_updates +#96 288 r 0 temporary_filler +0 384 r 0 reserved_memory +384 1 e 4 boot_option +385 1 e 4 last_boot +386 1 e 1 ECC_memory +388 4 r 0 reboot_bits +392 3 e 5 baud_rate +400 1 e 1 power_on_after_fail +412 4 e 6 debug_level +416 4 e 7 boot_first +420 4 e 7 boot_second +424 4 e 7 boot_third +428 4 h 0 boot_index +432 8 h 0 boot_countdown +1008 16 h 0 check_sum + +enumerations + +#ID value text +1 0 Disable +1 1 Enable +2 0 Enable +2 1 Disable +4 0 Fallback +4 1 Normal +5 0 115200 +5 1 57600 +5 2 38400 +5 3 19200 +5 4 9600 +5 5 4800 +5 6 2400 +5 7 1200 +6 6 Notice +6 7 Info +6 8 Debug +6 9 Spew +7 0 Network +7 1 HDD +7 2 Floppy +7 8 Fallback_Network +7 9 Fallback_HDD +7 10 Fallback_Floppy +#7 3 ROM + +checksums + +checksum 392 1007 1008 + + diff --git a/src/mainboard/bitworks/ims/debug.c b/src/mainboard/bitworks/ims/debug.c new file mode 100644 index 0000000000..7eeabdef47 --- /dev/null +++ b/src/mainboard/bitworks/ims/debug.c @@ -0,0 +1,66 @@ + +static void print_debug_pci_dev(unsigned dev) +{ + print_debug("PCI: "); + print_debug_hex8((dev >> 16) & 0xff); + print_debug_char(':'); + print_debug_hex8((dev >> 11) & 0x1f); + print_debug_char('.'); + print_debug_hex8((dev >> 8) & 7); +} + +static 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("\r\n"); + } +} + +static void dump_pci_device(unsigned dev) +{ + int i; + print_debug_pci_dev(dev); + print_debug("\r\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("\r\n"); + } + } +} + +static 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); + } +} diff --git a/src/mainboard/bitworks/ims/failover.c b/src/mainboard/bitworks/ims/failover.c new file mode 100644 index 0000000000..bdcb9eaed2 --- /dev/null +++ b/src/mainboard/bitworks/ims/failover.c @@ -0,0 +1,32 @@ +#define ASSEMBLY 1 +#include <stdint.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <arch/io.h> +#include "arch/romcc_io.h" +#include "pc80/mc146818rtc_early.c" + +static unsigned long main(unsigned long bist) +{ + /* This is the primary cpu how should I boot? */ + if (do_normal_boot()) { + goto normal_image; + } + else { + goto fallback_image; + } + normal_image: + asm volatile ("jmp __normal_image" + : /* outputs */ + : "a" (bist) /* inputs */ + : /* clobbers */ + ); + cpu_reset: + asm volatile ("jmp __cpu_reset" + : /* outputs */ + : "a"(bist) /* inputs */ + : /* clobbers */ + ); + fallback_image: + return bist; +} diff --git a/src/mainboard/bitworks/ims/irq_tables.c b/src/mainboard/bitworks/ims/irq_tables.c new file mode 100644 index 0000000000..894c27dec5 --- /dev/null +++ b/src/mainboard/bitworks/ims/irq_tables.c @@ -0,0 +1,32 @@ +/* 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 <arch/pirq_routing.h> + +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 */ + 0, /* Where the interrupt router lies (bus) */ + 0x88, /* Where the interrupt router lies (dev) */ + 0x1c20, /* IRQs devoted exclusively to PCI usage */ + 0x1106, /* Vendor */ + 0x8231, /* Device */ + 0, /* Crap (miniport) */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */ + 0x5e, /* u8 checksum , this hase to set to some value that would give 0 after the sum of all bytes for this structure (including checksum) */ + { + /* 8231 ethernet */ + {0,0x90, {{0x1, 0xdeb8}, {0x2, 0xdeb8}, {0x3, 0xdeb8}, {0x4, 0xdeb8}}, 0x1, 0}, + /* 8231 internal */ + {0,0x88, {{0x2, 0xdeb8}, {0x3, 0xdeb8}, {0x4, 0xdeb8}, {0x1, 0xdeb8}}, 0x2, 0}, + /* PCI slot */ + {0,0xa0, {{0x3, 0xdeb8}, {0x4, 0xdeb8}, {0x1, 0xdeb8}, {0x2, 0xdeb8}}, 0, 0}, + {0,0x50, {{0x4, 0xdeb8}, {0x3, 0xdeb8}, {0x2, 0xdeb8}, {0x1, 0xdeb8}}, 0x3, 0}, + {0,0x98, {{0x4, 0xdeb8}, {0x3, 0xdeb8}, {0x2, 0xdeb8}, {0x1, 0xdeb8}}, 0x4, 0}, + } +}; diff --git a/src/mainboard/bitworks/ims/mainboard.c b/src/mainboard/bitworks/ims/mainboard.c new file mode 100644 index 0000000000..28f46e700b --- /dev/null +++ b/src/mainboard/bitworks/ims/mainboard.c @@ -0,0 +1,12 @@ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <arch/io.h> +#include "chip.h" + +struct chip_operations mainboard_bitworks_ims_ops = { + CHIP_NAME("Bitworks IMS mainboard ") +}; + diff --git a/src/mainboard/bitworks/ims/reset.c b/src/mainboard/bitworks/ims/reset.c new file mode 100644 index 0000000000..5796e17dc8 --- /dev/null +++ b/src/mainboard/bitworks/ims/reset.c @@ -0,0 +1,43 @@ +#if 0 +//#include "arch/romcc_io.h" +#include <arch/io.h> + +typedef unsigned device_t; + +#define PCI_DEV(BUS, DEV, FN) ( \ + (((BUS) & 0xFF) << 16) | \ + (((DEV) & 0x1f) << 11) | \ + (((FN) & 0x7) << 8)) + +static void pci_write_config8(device_t dev, unsigned where, unsigned char value) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + outb(value, 0xCFC + (addr & 3)); +} + +static void pci_write_config32(device_t dev, unsigned where, unsigned value) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + outl(value, 0xCFC); +} + +static unsigned pci_read_config32(device_t dev, unsigned where) +{ + unsigned addr; + addr = dev | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + return inl(0xCFC); +} + +#include "../../../northbridge/amd/amdk8/reset_test.c" + +void hard_reset(void) +{ + set_bios_reset(); + pci_write_config8(PCI_DEV(1, 0x04, 0), 0x47, 1); +} +#endif diff --git a/src/northbridge/intel/i440bx/Config.lb b/src/northbridge/intel/i440bx/Config.lb new file mode 100644 index 0000000000..4a0c2c8658 --- /dev/null +++ b/src/northbridge/intel/i440bx/Config.lb @@ -0,0 +1,2 @@ +config chip.h +object northbridge.o diff --git a/src/northbridge/intel/i440bx/chip.h b/src/northbridge/intel/i440bx/chip.h new file mode 100644 index 0000000000..b0b3b72b4a --- /dev/null +++ b/src/northbridge/intel/i440bx/chip.h @@ -0,0 +1,5 @@ +struct northbridge_intel_i440bx_config +{ +}; + +extern struct chip_operations northbridge_intel_i440bx_ops; diff --git a/src/northbridge/intel/i440bx/northbridge.c b/src/northbridge/intel/i440bx/northbridge.c new file mode 100644 index 0000000000..ed262c24b7 --- /dev/null +++ b/src/northbridge/intel/i440bx/northbridge.c @@ -0,0 +1,186 @@ +#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 "chip.h" +#include "northbridge.h" + +/* +*/ +static void northbridge_init(device_t dev) +{ + printk_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 struct pci_driver northbridge_driver __pci_driver = { + .ops = &northbridge_operations, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x7190, +}; + + + +#define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM) + +static void pci_domain_read_resources(device_t dev) +{ + struct resource *resource; + + /* Initialize the system wide io space constraints */ + resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0,0)); + resource->limit = 0xffffUL; + resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + + /* Initialize the system wide memory resources constraints */ + resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1,0)); + resource->limit = 0xffffffffULL; + resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; +} + +static void ram_resource(device_t dev, unsigned long index, + unsigned long basek, unsigned long sizek) +{ + struct resource *resource; + + if (!sizek) { + return; + } + resource = new_resource(dev, index); + resource->base = ((resource_t)basek) << 10; + resource->size = ((resource_t)sizek) << 10; + resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | \ + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; +} + +static void tolm_test(void *gp, struct device *dev, struct resource *new) +{ + struct resource **best_p = gp; + struct resource *best; + best = *best_p; + if (!best || (best->base > new->base)) { + best = new; + } + *best_p = best; +} + +static uint32_t find_pci_tolm(struct bus *bus) +{ + struct resource *min; + uint32_t tolm; + min = 0; + search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min); + tolm = 0xffffffffUL; + if (min && tolm > min->base) { + tolm = min->base; + } + return tolm; +} + +static void pci_domain_set_resources(device_t dev) +{ + static const uint8_t ramregs[] = { + 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x56, 0x57 + }; + device_t mc_dev; + uint32_t pci_tolm; + + pci_tolm = find_pci_tolm(&dev->link[0]); + mc_dev = dev->link[0].children; + if (mc_dev) { + unsigned long tomk, tolmk; + unsigned char rambits; + int i, idx; + + for(rambits = 0, i = 0; i < sizeof(ramregs)/sizeof(ramregs[0]); i++) { + unsigned char reg; + reg = pci_read_config8(mc_dev, ramregs[i]); + /* these are ENDING addresses, not sizes. + * if there is memory in this slot, then reg will be > rambits. + * So we just take the max, that gives us total. + * We take the highest one to cover for once and future linuxbios + * bugs. We warn about bugs. + */ + if (reg > rambits) + rambits = reg; + if (reg < rambits) + printk_err("ERROR! register 0x%x is not set!\n", + ramregs[i]); + } + printk_debug("I would set ram size to 0x%x Kbytes\n", (rambits)*8*1024); + tomk = rambits*8*1024; + /* Compute the top of Low memory */ + tolmk = pci_tolm >> 10; + if (tolmk >= tomk) { + /* The PCI hole does does not overlap the memory. + */ + tolmk = tomk; + } + /* Report the memory regions */ + idx = 10; + ram_resource(dev, idx++, 0, tolmk); + } + assign_resources(&dev->link[0]); +} + +static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max) +{ + max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max); + return max; +} + +static struct device_operations pci_domain_ops = { + .read_resources = pci_domain_read_resources, + .set_resources = pci_domain_set_resources, + .enable_resources = enable_childrens_resources, + .init = 0, + .scan_bus = pci_domain_scan_bus, +}; + +static void cpu_bus_init(device_t dev) +{ + initialize_cpus(&dev->link[0]); +} + +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_i440bx_ops = { + CHIP_NAME("Intel 440bx Northbridge") + .enable_dev = enable_dev, +}; diff --git a/src/northbridge/intel/i440bx/northbridge.h b/src/northbridge/intel/i440bx/northbridge.h new file mode 100644 index 0000000000..3e569bb31b --- /dev/null +++ b/src/northbridge/intel/i440bx/northbridge.h @@ -0,0 +1,6 @@ +#ifndef NORTHBRIDGE_INTEL_440BX_H +#define NORTHBRIDGE_INTEL_440BX_H + +extern unsigned int i440bx_scan_root_bus(device_t root, unsigned int max); + +#endif /* NORTHBRIDGE_INTEL_440BX_H */ diff --git a/src/northbridge/intel/i440bx/raminit.c b/src/northbridge/intel/i440bx/raminit.c new file mode 100644 index 0000000000..737f2bf458 --- /dev/null +++ b/src/northbridge/intel/i440bx/raminit.c @@ -0,0 +1,399 @@ +#include <cpu/x86/mtrr.h> +#include "raminit.h" + +/* +This software and ancillary information (herein called SOFTWARE ) +called LinuxBIOS is made available under the terms described +here. The SOFTWARE has been approved for release with associated +LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has +been authored by an employee or employees of the University of +California, operator of the Los Alamos National Laboratory under +Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The +U.S. Government has rights to use, reproduce, and distribute this +SOFTWARE. The public may copy, distribute, prepare derivative works +and publicly display this SOFTWARE without charge, provided that this +Notice and any statement of authorship are reproduced on all copies. +Neither the Government nor the University makes any warranty, express +or implied, or assumes any liability or responsibility for the use of +this SOFTWARE. If SOFTWARE is modified to produce derivative works, +such modified SOFTWARE should be clearly marked, so as not to confuse +it with the version available from LANL. + */ +/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL + * rminnich@lanl.gov + */ +/* + * 11/26/02 - kevinh@ispiri.com - The existing comments implied that + * this didn't work yet. Therefore, I've updated it so that it works + * correctly - at least on my VIA epia motherboard. 64MB DIMM in slot 0. + */ + +/* Added automatic detection of first equipped bank and its MA mapping type. + * (Rest of configuration is done in C) + * 5/19/03 by SONE Takeshi <ts1@tsn.or.jp> + */ +/* converted to C 9/2003 Ron Minnich */ + +/* Modified for the i440bx Richard Smith 01/2005 */ + +/* Set to 1 if your DIMMs are PC133 Note that I'm assuming CPU's FSB + * frequency is 133MHz. If your CPU runs at another bus speed, you + * might need to change some of register values. + */ +#ifndef DIMM_PC133 +#define DIMM_PC133 0 +#endif + +// Set to 1 if your DIMMs are CL=2 +#ifndef DIMM_CL2 +#define DIMM_CL2 0 +#endif + +void dimms_read(unsigned long x) +{ + uint8_t c; + unsigned long eax; + volatile unsigned long y; + eax = x; + for(c = 0; c < 6; c++) { + y = * (volatile unsigned long *) eax; + eax += 0x10000000; + } +} + +void dimms_write(int x) +{ + uint8_t c; + unsigned long eax = x; + for(c = 0; c < 6; c++) { + *(volatile unsigned long *) eax = 0; + eax += 0x10000000; + } +} + + + +#ifdef DEBUG_SETNORTHB +void setnorthb(device_t north, uint8_t reg, uint8_t val) +{ + print_debug("setnorth: reg "); + print_debug_hex8(reg); + print_debug(" to "); + print_debug_hex8(val); + print_debug("\r\n"); + pci_write_config8(north, reg, val); +} +#else +#define setnorthb pci_write_config8 +#endif + +void +dumpnorth(device_t north) +{ + unsigned int r, c; + for(r = 0; ; r += 16) { + print_debug_hex8(r); + print_debug(":"); + for(c = 0; c < 16; c++) { + print_debug_hex8(pci_read_config8(north, r+c)); + print_debug(" "); + } + print_debug("\r\n"); + if (r >= 240) + break; + } +} + +static void sdram_set_registers(const struct mem_controller *ctrl) +{ + device_t north = (device_t) 0; + uint8_t c, r; + + print_err("vt8601 init starting\r\n"); + north = pci_locate_device(PCI_ID(0x1106, 0x8601), 0); + north = 0; + print_debug_hex32(north); + print_debug(" is the north\n"); + print_debug_hex16(pci_read_config16(north, 0)); + print_debug(" "); + print_debug_hex16(pci_read_config16(north, 2)); + print_debug("\r\n"); + + /* All we are doing now is setting initial known-good values that will + * be revised later as we read SPD + */ + // memory clk enable. We are not using ECC + pci_write_config8(north,0x78, 0x01); + print_debug_hex8(pci_read_config8(north, 0x78)); + // dram control, see the book. +#if DIMM_PC133 + pci_write_config8(north,0x68, 0x52); +#else + pci_write_config8(north,0x68, 0x42); +#endif + // dram control, see the book. + pci_write_config8(north,0x6B, 0x0c); + // Initial setting, 256MB in each bank, will be rewritten later. + pci_write_config8(north,0x5A, 0x20); + print_debug_hex8(pci_read_config8(north, 0x5a)); + pci_write_config8(north,0x5B, 0x40); + pci_write_config8(north,0x5C, 0x60); + pci_write_config8(north,0x5D, 0x80); + pci_write_config8(north,0x5E, 0xA0); + pci_write_config8(north,0x5F, 0xC0); + // It seems we have to take care of these 2 registers as if + // they are bank 6 and 7. + pci_write_config8(north,0x56, 0xC0); + pci_write_config8(north,0x57, 0xC0); + + // SDRAM in all banks + pci_write_config8(north,0x60, 0x3F); + // DRAM timing. I'm suspicious of this + // This is for all banks, 64 is 0,1. 65 is 2,3. 66 is 4,5. + // ras precharge 4T, RAS pulse 5T + // cas2 is 0xd6, cas3 is 0xe6 + // we're also backing off write pulse width to 2T, so result is 0xee +#if DIMM_CL2 + pci_write_config8(north,0x64, 0xd4); + pci_write_config8(north,0x65, 0xd4); + pci_write_config8(north,0x66, 0xd4); +#else // CL=3 + pci_write_config8(north,0x64, 0xe4); + pci_write_config8(north,0x65, 0xe4); + pci_write_config8(north,0x66, 0xe4); +#endif + + // dram frequency select. + // enable 4K pages for 64M dram. +#if DIMM_PC133 + pci_write_config8(north,0x69, 0x3c); +#else + pci_write_config8(north,0x69, 0xac); +#endif + + /* IMPORTANT -- disable refresh counter */ + // refresh counter, disabled. + pci_write_config8(north,0x6A, 0x00); + + + // clkenable configuration. kevinh FIXME - add precharge + pci_write_config8(north,0x6C, 0x00); + // dram read latch delay of 1 ns, MD drive 8 mA, + // high drive strength on MA[2: 13], we#, cas#, ras# + // As per Cindy Lee, set to 0x37, not 0x57 + pci_write_config8(north,0x6D, 0x7f); +} + +/* slot is the dram slot. Return size of side0 in lower 16-bit, + * side1 in upper 16-bit, in units of 8MB */ +static unsigned long +spd_module_size(unsigned char slot) +{ + /* for all the DRAMS, see if they are there and get the size of each + * module. This is just a very early first cut at sizing. + */ + /* we may run out of registers ... */ + unsigned int banks, rows, cols, reg; + unsigned int value = 0; + /* unsigned int module = ((0x50 + slot) << 1) + 1; */ + unsigned int module = 0x50 + slot; + /* is the module there? if byte 2 is not 4, then we'll assume it + * is useless. + */ + print_info("Slot "); + print_info_hex8(slot); + if (smbus_read_byte(module, 2) != 4) { + print_info(" is empty\r\n"); + return 0; + } + print_info(" is SDRAM "); + + banks = smbus_read_byte(module, 17); + /* we're going to assume symmetric banks. Sorry. */ + cols = smbus_read_byte(module, 4) & 0xf; + rows = smbus_read_byte(module, 3) & 0xf; + /* grand total. You have rows+cols addressing, * times of banks, times + * width of data in bytes */ + /* Width is assumed to be 64 bits == 8 bytes */ + value = (1 << (cols + rows)) * banks * 8; + print_info_hex32(value); + print_info(" bytes "); + /* Return in 8MB units */ + value >>= 23; + + /* We should have single or double side */ + if (smbus_read_byte(module, 5) == 2) { + print_info("x2"); + value = (value << 16) | value; + } + print_info("\r\n"); + return value; + +} + +static int +spd_num_chips(unsigned char slot) +{ +/* unsigned int module = ((0x50 + slot) << 1) + 1; */ + unsigned int module = 0x50 + slot; + unsigned int width; + + width = smbus_read_byte(module, 13); + if (width == 0) + width = 8; + return 64 / width; +} + +static void sdram_set_spd_registers(const struct mem_controller *ctrl) +{ +#define T133 7 + unsigned char Trp = 1, Tras = 1, casl = 2, val; + unsigned char timing = 0xe4; + /* read Trp */ + val = smbus_read_byte(0x50, 27); + if (val < 2*T133) + Trp = 1; + val = smbus_read_byte(0x50, 30); + if (val < 5*T133) + Tras = 0; + val = smbus_read_byte(0x50, 18); + if (val < 8) + casl = 1; + if (val < 4) + casl = 0; + + val = (Trp << 7) | (Tras << 6) | (casl << 4) | 4; + + print_debug_hex8(val); print_debug(" is the computed timing\n"); + /* don't set it. Experience shows that this screwy chipset should just + * be run with the most conservative timing. + * pci_write_config8(0, 0x64, val); + */ +} + +static void set_ma_mapping(device_t north, int slot, int type) +{ + unsigned char reg, val; + int shift; + + reg = 0x58 + slot/2; + if (slot%2 >= 1) + shift = 0; + else + shift = 4; + + val = pci_read_config8(north, reg); + val &= ~(0xf << shift); + val |= type << shift; + pci_write_config8(north, reg, val); +} + + +static void sdram_enable(int controllers, const struct mem_controller *ctrl) +{ + unsigned char i; + static const uint8_t ramregs[] = { + 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x56, 0x57 + }; + device_t north = 0; + uint32_t size, base, slot, ma; + /* begin to initialize*/ + // I forget why we need this, but we do + dimms_write(0xa55a5aa5); + + /* set NOP*/ + pci_write_config8(north,0x6C, 0x01); + print_debug("NOP\r\n"); + /* wait 200us*/ + // You need to do the memory reference. That causes the nop cycle. + dimms_read(0); + udelay(400); + print_debug("PRECHARGE\r\n"); + /* set precharge */ + pci_write_config8(north,0x6C, 0x02); + print_debug("DUMMY READS\r\n"); + /* dummy reads*/ + dimms_read(0); + udelay(200); + print_debug("CBR\r\n"); + /* set CBR*/ + pci_write_config8(north,0x6C, 0x04); + + /* do 8 reads and wait >100us between each - from via*/ + dimms_read(0); + udelay(200); + dimms_read(0); + udelay(200); + dimms_read(0); + udelay(200); + dimms_read(0); + udelay(200); + dimms_read(0); + udelay(200); + dimms_read(0); + udelay(200); + dimms_read(0); + udelay(200); + dimms_read(0); + udelay(200); + print_debug("MRS\r\n"); + /* set MRS*/ + pci_write_config8(north,0x6c, 0x03); +#if DIMM_CL2 + dimms_read(0x150); +#else // CL=3 + dimms_read(0x1d0); +#endif + udelay(200); + print_debug("NORMAL\r\n"); + /* set to normal mode */ + pci_write_config8(north,0x6C, 0x08); + + dimms_write(0x55aa55aa); + dimms_read(0); + udelay(200); + print_debug("set ref. rate\r\n"); + // Set the refresh rate. +#if DIMM_PC133 + pci_write_config8(north,0x6A, 0x86); +#else + pci_write_config8(north,0x6A, 0x65); +#endif + print_debug("enable multi-page open\r\n"); + // enable multi-page open + pci_write_config8(north,0x6B, 0x0d); + + base = 0; + for(slot = 0; slot < 4; slot++) { + size = spd_module_size(slot); + /* side 0 */ + base += size & 0xffff; + pci_write_config8(north, ramregs[2*slot], base); + /* side 1 */ + base += size >> 16; + if (base > 0xff) + base = 0xff; + pci_write_config8(north, ramregs[2*slot + 1], base); + + if (!size) + continue; + + /* Calculate the value of MA mapping type register, + * based on size of SDRAM chips. */ + size = (size & 0xffff) << (3 + 3); + /* convert module size to be in Mbits */ + size /= spd_num_chips(slot); + print_debug_hex16(size); + print_debug(" is the chip size\r\n"); + if (size < 64) + ma = 0; + if (size < 256) + ma = 8; + else + ma = 0xe; + print_debug_hex16(ma); + print_debug(" is the MA type\r\n"); + set_ma_mapping(north, slot, ma); + } + print_err("vt8601 done\r\n"); +} diff --git a/src/northbridge/intel/i440bx/raminit.h b/src/northbridge/intel/i440bx/raminit.h new file mode 100644 index 0000000000..6e40683066 --- /dev/null +++ b/src/northbridge/intel/i440bx/raminit.h @@ -0,0 +1,11 @@ +#ifndef RAMINIT_H +#define RAMINIT_H + +#define DIMM_SOCKETS 4 +struct mem_controller { + device_t d0; + uint16_t channel0[DIMM_SOCKETS]; +}; + + +#endif /* RAMINIT_H */ diff --git a/src/southbridge/intel/i440bx/chip.h b/src/southbridge/intel/i440bx/chip.h new file mode 100644 index 0000000000..5952e38582 --- /dev/null +++ b/src/southbridge/intel/i440bx/chip.h @@ -0,0 +1,13 @@ +#ifndef I440BX_CHIP_H +#define I440BX_CHIP_H + +struct southbridge_intel_i440bx_config +{ + unsigned int ide0_enable : 1; + unsigned int ide1_enable : 1; +}; + +struct chip_operations; +extern struct chip_operations southbridge_intel_i440bx_ops; + +#endif /* I440BX_CHIP_H */ diff --git a/src/southbridge/intel/i440bx/i440bx_early_smbus.c b/src/southbridge/intel/i440bx/i440bx_early_smbus.c new file mode 100644 index 0000000000..a3db7b88c0 --- /dev/null +++ b/src/southbridge/intel/i440bx/i440bx_early_smbus.c @@ -0,0 +1,45 @@ +#include "i440bx_smbus.h" + +#define SMBUS_IO_BASE 0x0f00 + +static void enable_smbus(void) +{ + device_t dev; + dev = pci_locate_device(PCI_ID(0x8086, 0x7113), 0); + if (dev == PCI_DEV_INVALID) { + die("SMBUS controller not found\r\n"); + } + uint8_t enable; + print_spew("SMBus controller enabled\r\n"); + pci_write_config32(dev, 0x90, SMBUS_IO_BASE ); + // Enable and set SMBBus + // 0x01 Interrupt to SMI# + // (0x4<<1)|1 set interrupt to IRQ9 + pci_write_config8(dev, 0xd2, (0x4<<1)|1); + + // Enable the IO space + pci_write_config16(dev, 0x04, 1); + + /* clear any lingering errors, so the transaction will run */ + outb(0x1e, SMBUS_IO_BASE + SMBGSTATUS); +} + +static int smbus_recv_byte(unsigned device) +{ + return do_smbus_recv_byte(SMBUS_IO_BASE, device); +} + +static int smbus_send_byte(unsigned device, unsigned char val) +{ + return do_smbus_send_byte(SMBUS_IO_BASE, device, val); +} + +static int smbus_read_byte(unsigned device, unsigned address) +{ + return do_smbus_read_byte(SMBUS_IO_BASE, device, address); +} + +static int smbus_write_byte(unsigned device, unsigned address, unsigned char val) +{ + return do_smbus_write_byte(SMBUS_IO_BASE, device, address, val); +} diff --git a/src/southbridge/intel/i440bx/i440bx_smbus.c b/src/southbridge/intel/i440bx/i440bx_smbus.c new file mode 100644 index 0000000000..9609e357c1 --- /dev/null +++ b/src/southbridge/intel/i440bx/i440bx_smbus.c @@ -0,0 +1,43 @@ +/* + * (C) 2004 Linux Networx + * (C) 2005 Bitworks +*/ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <device/smbus.h> +#include <arch/io.h> +#include "i440bx.h" + + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x44, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct smbus_bus_operations lops_smbus_bus = { +}; + +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; +static struct device_operations smbus_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = 0, + .scan_bus = scan_static_bus, + .enable = i440bx_enable, + .ops_pci = &lops_pci, + .ops_smbus_bus = &lops_smbus_bus, +}; + +static struct pci_driver smbus_driver __pci_driver = { + .ops = &smbus_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_INTEL_440BX_SMB, +}; diff --git a/src/southbridge/intel/i440bx/i440bx_smbus.h b/src/southbridge/intel/i440bx/i440bx_smbus.h new file mode 100644 index 0000000000..9a100c0f8b --- /dev/null +++ b/src/southbridge/intel/i440bx/i440bx_smbus.h @@ -0,0 +1,230 @@ +#include <device/smbus_def.h> + +#define SMBGSTATUS 0x0 +#define SMBGCTL 0x2 +#define SMBHSTCMD 0x3 +#define SMBHSTADDR 0x4 +#define SMBHSTDAT 0x5 + +#define SMBUS_TIMEOUT (100*1000*10) +#define SMBUS_STATUS_MASK 0x1e + +static inline void smbus_delay(void) +{ + outb(0x80, 0x80); + outb(0x80, 0x80); + outb(0x80, 0x80); + outb(0x80, 0x80); + outb(0x80, 0x80); + outb(0x80, 0x80); +} + +static int smbus_wait_until_ready(unsigned smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned char val; + smbus_delay(); + val = inb(smbus_io_base + SMBGSTATUS); + if ((val & 0x1) == 0) { + break; + } + if(loops == (SMBUS_TIMEOUT / 2)) { + outw(inw(smbus_io_base + SMBGSTATUS), + smbus_io_base + SMBGSTATUS); + } + } while(--loops); + return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT; +} + +static int smbus_wait_until_done(unsigned smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned short val; + smbus_delay(); + + val = inb(smbus_io_base + SMBGSTATUS); + // Make sure the command is done + if ((val & 0x1) != 0) { + continue; + } + // Don't break out until one of the interrupt + // flags is set. + if (val & 0xfe) { + break; + } + } while(--loops); + return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT; +} + +static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device) +{ + unsigned global_status_register; + unsigned byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(0, smbus_io_base + SMBHSTCMD); + /* set up for a send byte */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* set the data word...*/ + outw(0, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + } + + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + /* read results of transaction */ + byte = inb(smbus_io_base + SMBHSTDAT) & 0xff; + + // Check for any result other than a command completion + if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 1)) { + return SMBUS_ERROR; + } + return byte; +} + +static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value) +{ + unsigned global_status_register; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(0, smbus_io_base + SMBHSTCMD); + /* set up for a send byte */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* set the data word...*/ + outw(value, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + } + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) { + return SMBUS_ERROR; + } + return 0; +} + + +static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address) +{ + unsigned global_status_register; + unsigned byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + } + + /* setup transaction */ + + /* clear any lingering errors, so the transaction will run */ + outb(0x1e, smbus_io_base + SMBGSTATUS); + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(address & 0xFF, smbus_io_base + SMBHSTCMD); + + /* clear the data word...*/ + outb(0, smbus_io_base + SMBHSTDAT); + + /* start a byte read with interrupts disabled */ + outb( (0x02 << 2)|(1<<6), smbus_io_base + SMBGCTL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + } + + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + /* read results of transaction */ + byte = inw(smbus_io_base + SMBHSTDAT) & 0xff; + + if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) { + return SMBUS_ERROR; + } + return byte; +} + +static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val) +{ + unsigned global_status_register; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR); + outb(address & 0xFF, smbus_io_base + SMBHSTCMD); + /* set up for a byte data write */ /* FIXME */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL); + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* write the data word...*/ + outw(val, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + } + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) { + return SMBUS_ERROR; + } + return 0; +} + diff --git a/src/superio/NSC/pc87351/Config.lb b/src/superio/NSC/pc87351/Config.lb new file mode 100644 index 0000000000..f62a567d61 --- /dev/null +++ b/src/superio/NSC/pc87351/Config.lb @@ -0,0 +1,2 @@ +config chip.h +object superio.o diff --git a/src/superio/NSC/pc87351/chip.h b/src/superio/NSC/pc87351/chip.h new file mode 100644 index 0000000000..6b62c5493d --- /dev/null +++ b/src/superio/NSC/pc87351/chip.h @@ -0,0 +1,17 @@ +#ifndef SIO_COM1 +#define SIO_COM1_BASE 0x3F8 +#endif +#ifndef SIO_COM2 +#define SIO_COM2_BASE 0x2F8 +#endif + +struct chip_operations; +extern struct chip_operations superio_NSC_pc87351_ops; + +#include <pc80/keyboard.h> +#include <uart8250.h> + +struct superio_NSC_pc87351_config { + struct uart8250 com1, com2; + struct pc_keyboard keyboard; +}; diff --git a/src/superio/NSC/pc87351/pc87351.h b/src/superio/NSC/pc87351/pc87351.h new file mode 100644 index 0000000000..dbed582bce --- /dev/null +++ b/src/superio/NSC/pc87351/pc87351.h @@ -0,0 +1,9 @@ +#define PC87351_FDC 0x00 /* Floppy */ +#define PC87351_PP 0x01 /* Parallel port */ +#define PC87351_SP2 0x02 /* Com2 */ +#define PC87351_SP1 0x03 /* Com1 */ +#define PC87351_SWC 0x04 /* System wakeup control */ +#define PC87351_KBCM 0x05 /* Mouse */ +#define PC87351_KBCK 0x06 /* Keyboard */ +#define PC87351_GPIO 0x07 /* General purpose IO */ +#define PC87351_FSD 0x08 /* Fan speed device */ diff --git a/src/superio/NSC/pc87351/pc87351_early_serial.c b/src/superio/NSC/pc87351/pc87351_early_serial.c new file mode 100644 index 0000000000..7ec361e853 --- /dev/null +++ b/src/superio/NSC/pc87351/pc87351_early_serial.c @@ -0,0 +1,10 @@ +#include <arch/romcc_io.h> +#include "pc87351.h" + +static void pc87351_enable_serial(device_t dev, unsigned iobase) +{ + pnp_set_logical_device(dev); + pnp_set_enable(dev, 0); + pnp_set_iobase(dev, PNP_IDX_IO0, iobase); + pnp_set_enable(dev, 1); +} diff --git a/src/superio/NSC/pc87351/superio.c b/src/superio/NSC/pc87351/superio.c new file mode 100644 index 0000000000..a106d3a947 --- /dev/null +++ b/src/superio/NSC/pc87351/superio.c @@ -0,0 +1,80 @@ +/* Copyright 2000 AG Electronics Ltd. */ +/* Copyright 2003-2004 Linux Networx */ +/* This code is distributed without warranty under the GPL v2 (see COPYING) */ + +/* + * Richard A Smith + * I derived this code from the pc87360 device and removed the stuff the 87351 + * dosen't do. +*/ + +#include <arch/io.h> +#include <device/device.h> +#include <device/pnp.h> +#include <console/console.h> +#include <string.h> +#include <bitops.h> +#include <uart8250.h> +#include <pc80/keyboard.h> +#include "chip.h" +#include "pc87351.h" + +static void init(device_t dev) +{ + struct superio_NSC_pc87351_config *conf; + struct resource *res0, *res1; + /* Wishlist handle well known programming interfaces more + * generically. + */ + if (!dev->enabled) { + return; + } + conf = dev->chip_info; + switch(dev->path.u.pnp.device) { + case PC87351_SP1: + res0 = find_resource(dev, PNP_IDX_IO0); + init_uart8250(res0->base, &conf->com1); + break; + case PC87351_SP2: + res0 = find_resource(dev, PNP_IDX_IO0); + init_uart8250(res0->base, &conf->com2); + break; + case PC87351_KBCK: + res0 = find_resource(dev, PNP_IDX_IO0); + res1 = find_resource(dev, PNP_IDX_IO1); + init_pc_keyboard(res0->base, res1->base, &conf->keyboard); + break; + } +} + +static struct device_operations ops = { + .read_resources = pnp_read_resources, + .set_resources = pnp_set_resources, + .enable_resources = pnp_enable_resources, + .enable = pnp_enable, + .init = init, +}; + +static struct pnp_info pnp_dev_info[] = { + { &ops, PC87351_FDC, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07fa, 0}, }, + { &ops, PC87351_PP, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x04f8, 0}, }, + { &ops, PC87351_SP2, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_DRQ1, { 0x7f8, 0 }, }, + { &ops, PC87351_SP1, PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, }, + { &ops, PC87351_SWC, PNP_IO0 | PNP_IRQ0, { 0xfff0, 0 }, }, + { &ops, PC87351_KBCM, PNP_IRQ0 }, + { &ops, PC87351_KBCK, PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7f8, 0 }, { 0x7f8, 0x4}, }, + { &ops, PC87351_GPIO, PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } }, + { &ops, PC87351_FSD, PNP_IO0 | PNP_IRQ0, { 0xfff8, 0 } }, +}; + + +static void enable_dev(struct device *dev) +{ + pnp_enable_devices(dev, &pnp_ops, + sizeof(pnp_dev_info)/sizeof(pnp_dev_info[0]), pnp_dev_info); +} + +struct chip_operations superio_NSC_pc87351_ops = { + CHIP_NAME("NSC 87351") + .enable_dev = enable_dev, +}; |