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
This commit is contained in:
Richard Smith 2006-07-24 04:25:47 +00:00
parent 4788effb04
commit cb8eab482f
29 changed files with 1811 additions and 0 deletions

View File

@ -0,0 +1,3 @@
config chip.h
object socket_PGA370.o
dir /cpu/intel/model_6xx

View File

@ -0,0 +1,4 @@
extern struct chip_operations cpu_intel_socket_PGA370_ops;
struct cpu_intel_socket_PGA370_config {
};

View File

@ -0,0 +1,7 @@
#include <device/device.h>
#include "chip.h"
struct chip_operations cpu_intel_socket_PGA370_ops = {
CHIP_NAME("socket PGA370")
};

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -0,0 +1,5 @@
extern struct chip_operations mainboard_bitworks_ims_ops;
struct mainboard_bitworks_ims_config {
int nothing;
};

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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},
}
};

View File

@ -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 ")
};

View File

@ -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

View File

@ -0,0 +1,2 @@
config chip.h
object northbridge.o

View File

@ -0,0 +1,5 @@
struct northbridge_intel_i440bx_config
{
};
extern struct chip_operations northbridge_intel_i440bx_ops;

View File

@ -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,
};

View File

@ -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 */

View File

@ -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");
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}

View File

@ -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,
};

View File

@ -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;
}

View File

@ -0,0 +1,2 @@
config chip.h
object superio.o

View File

@ -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;
};

View File

@ -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 */

View File

@ -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);
}

View File

@ -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,
};

View File

@ -0,0 +1,29 @@
# Config file for the Bitworks ims board
# This will make a target directory of ./ims
target ims
mainboard bitworks/ims
option ROM_SIZE=524288
romimage "normal"
option USE_FALLBACK_IMAGE=0
option ROM_IMAGE_SIZE=0x10000
option LINUXBIOS_EXTRA_VERSION=".0Normal"
# payload /usr/share/etherboot/5.1.9pre2-lnxi-lb/tg3--ide_disk.zelf
# payload ../../../../tg3--ide_disk.zelf
# payload ../../../../../lnxieepro100.ebi
payload /etc/hosts
end
romimage "fallback"
option USE_FALLBACK_IMAGE=1
option ROM_IMAGE_SIZE=0x10000
option LINUXBIOS_EXTRA_VERSION=".0Fallback"
# payload /usr/share/etherboot/5.1.9pre2-lnxi-lb/tg3--ide_disk.zelf
# payload ../../../../tg3--ide_disk.zelf
# payload ../../../../../lnxieepro100.ebia
payload /etc/hosts
end
buildrom ./linuxbios.rom ROM_SIZE "normal" "fallback"