Start of merge from work on the AMD760MP platform.

This is the safe part just additions to files, and comment changes
This commit is contained in:
Eric W. Biederman 2001-08-07 19:46:37 +00:00
commit 228148aa23
63 changed files with 6591 additions and 3 deletions

View file

@ -0,0 +1,30 @@
#ifndef ASM_H
#define ASM_H
#define ASSEMBLER
/*
* Bootstrap code for the STPC Consumer
* Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
*
* $Id$
*
*/
#define I386_ALIGN_TEXT 0
#define I386_ALIGN_DATA 0
/*
* XXX
*/
#ifdef __ELF__
#define EXT(x) x
#else
#define EXT(x) _ ## x
#endif
#define STATIC(x) .align I386_ALIGN_TEXT; EXT(x):
#define GLOBAL(x) .globl EXT(x); STATIC(x)
#define ENTRY(x) .text; GLOBAL(x)
#endif /* ASM_H */

View file

@ -0,0 +1,7 @@
#ifndef I386_SUBR_H
#define I386_SUBR_H
void cache_on(unsigned long totalram);
void interrupts_on(void);
#endif /* I386_SUBR_H */

View file

@ -0,0 +1,369 @@
/*
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
*/
#ifndef ROM_INTEL_H
#define ROM_INTEL_H
/*
* Bootstrap code for the Intel
*
* $Id$
*
*/
/*
* Config registers.
*/
/* yeah, yeah, I know these are macros, which is bad. Don't forget:
* we have almost no assembly, so I am not worrying just yet about this.
* we'll fix it someday if we care. My guess is we won't.
*/
/* well we want functions. But first we want to see it work at all. */
#undef FUNCTIONS
#ifndef FUNCTIONS
#define RET_LABEL(label) \
jmp label##_done
#define CALL_LABEL(label) \
jmp label ;\
label##_done:
#define CALLSP(func) \
lea 0f, %esp ; \
jmp func ; \
0:
#define RETSP \
jmp *%esp
#define DELAY(x) mov x, %ecx ;\
1: loop 1b ;\
/*
* Macro: PCI_WRITE_CONFIG_BYTE
* Arguments: %eax address to write to (includes bus, device, function, &offset)
* %dl byte to write
*
* Results: none
*
* Trashed: %eax, %edx
* Effects: writes a single byte to pci config space
*
* Notes: This routine is optimized for minimal register usage.
* And the tricks it does cannot scale beyond writing a single byte.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the data byte
* in the high half of edx.
*
* In %edx[3] it stores the byte to write.
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_WRITE_CONFIG_BYTE \
shll $8, %edx ; \
movb %al, %dl ; \
andb $0x3, %dl ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
movb %dh, %al ; \
movb $0, %dh ; \
addl $0xcfc, %edx ; \
outb %al, %dx
/*
* Macro: PCI_WRITE_CONFIG_WORD
* Arguments: %eax address to write to (includes bus, device, function, &offset)
* %ecx word to write
*
* Results: none
*
* Trashed: %eax, %edx
* Preserved: %ecx
* Effects: writes a single byte to pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_WRITE_CONFIG_WORD \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
movl %ecx, %eax ; \
addl $0xcfc, %edx ; \
outw %ax, %dx
/*
* Macro: PCI_WRITE_CONFIG_DWORD
* Arguments: %eax address to write to (includes bus, device, function, &offset)
* %ecx dword to write
*
* Results: none
*
* Trashed: %eax, %edx
* Preserved: %ecx
* Effects: writes a single byte to pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_WRITE_CONFIG_DWORD \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
movl %ecx, %eax ; \
addl $0xcfc, %edx ; \
outl %eax, %dx
/*
* Macro: PCI_READ_CONFIG_BYTE
* Arguments: %eax address to read from (includes bus, device, function, &offset)
*
* Results: %al Byte read
*
* Trashed: %eax, %edx
* Effects: reads a single byte from pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_READ_CONFIG_BYTE \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
addl $0xcfc, %edx ; \
inb %dx, %al
/*
* Macro: PCI_READ_CONFIG_WORD
* Arguments: %eax address to read from (includes bus, device, function, &offset)
*
* Results: %ax word read
*
* Trashed: %eax, %edx
* Effects: reads a 2 bytes from pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_READ_CONFIG_WORD \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
addl $0xcfc, %edx ; \
inw %dx, %ax
/*
* Macro: PCI_READ_CONFIG_DWORD
* Arguments: %eax address to read from (includes bus, device, function, &offset)
*
* Results: %eax
*
* Trashed: %edx
* Effects: reads 4 bytes from pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_READ_CONFIG_DWORD \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
addl $0xcfc, %edx ; \
inl %dx, %eax
#define CS_READ(which) \
mov $0x80000000,%eax ; \
mov which,%ax ; \
and $0xfc,%al /* clear bits 1-0 */ ; \
mov $0xcf8,%dx /* port 0xcf8 ?*/ ; \
outl %eax,%dx /* open up CS config */ ; \
add $0x4,%dl /* 0xcfc data port 0 */ ; \
mov which,%al ; \
and $0x3,%al /* only bits 1-0 */ ; \
add %al,%dl ; \
inb %dx,%al /* read */ ; \
#define CS_WRITE(which, data) \
mov $0x80000000,%eax /* 32bit word with bit 31 set */ ; \
mov which,%ax /* put the reg# in the low part */ ; \
and $0xfc,%al /* dword align the reg# */ ; \
mov $0xcf8,%dx /* enable port */ ; \
outl %eax,%dx ; \
add $0x4,%dl /* 1st data port */ ; \
mov which,%ax /* register# */ ; \
and $0x3,%ax ; \
add %al,%dl ; \
mov data, %al ; \
outb %al,%dx /* write to reg */
#define REGBIS(which, bis) \
CS_READ(which) ;\
movb bis, %cl ;\
orb %al, %cl ;\
CS_WRITE(which, %cl)
#define REGBIC(which, bic) \
CS_READ(which) ;\
movb bic, %cl ;\
notb %cl ;\
andb %al, %cl ;\
CS_WRITE(which, %cl)
/* macro to BIC and BIS a reg. calls read a reg,
* does a BIC and then a BIS on it.
* to clear no bits, make BIC 0.
* to set no bits, make BIS 0
*/
#define REGBICBIS(which, bic, bis) \
CS_READ(which) ;\
movb bic, %cl ;\
notb %cl ;\
andb %cl, %al ;\
movb bis, %cl ;\
orb %al, %cl ;\
CS_WRITE(which, %cl)
#else
NO FUNCTIONS YET!
#endif
/* originally this macro was from STPC BIOS */
#define intel_chip_post_macro(value) \
movb $value, %al ; \
outb %al, $0x80
#define INTEL_PDATA_MAGIC 0xdeadbeef
/* SLOW_DOWN_IO is a delay we can use that is roughly cpu neutral,
* and can be used before memory or timer chips come up.
* Since this hits the isa bus it's roughly
*/
#define SLOW_DOWN_IO inb $0x80, %al
#endif /* ROM_INTEL_H */

View file

@ -0,0 +1,11 @@
#ifndef ARCH_IOAPIC_H
#define ARCH_IOAPIC_H
#ifdef IOAPIC
extern void setup_ioapic(void);
#else
#define setup_ioapic() do {} while(0)
#endif
#endif /* ARCH_IOAPIC_H */

View file

@ -0,0 +1,21 @@
#ifndef ARCH_PIRQ_ROUTING_H
#define ARCH_PIRQ_ROUTING_H
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
#define PIRQ_VERSION 0x0100
extern const struct irq_routing_table intel_irq_routing_table;
#if !defined(DEBUG) && defined(HAVE_PIRQ_TABLE)
void check_pirq_routing_table(void);
#else
#define check_pirq_routing_table() do {} while(0)
#endif
#if defined(HAVE_PIRQ_ROUTING_TABLE)
void copy_pirq_routing_table(void);
#else
#define copy_pirq_routing_table() do {} while(0)
#endif
#endif /* ARCH_PIRQ_ROUTING_H */

View file

@ -0,0 +1,69 @@
#ifndef ARCH_SMP_ATOMIC_H
#define ARCH_SMP_ATOMIC_H
/*
* Make sure gcc doesn't try to be clever and move things around
* on us. We need to use _exactly_ the address the user gave us,
* not some alias that contains the same information.
*/
typedef struct { volatile int counter; } atomic_t;
#define ATOMIC_INIT(i) { (i) }
/*
* Atomic operations that C can't guarantee us. Useful for
* resource counting etc..
*/
/**
* atomic_read - read atomic variable
* @v: pointer of type atomic_t
*
* Atomically reads the value of @v. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_read(v) ((v)->counter)
/**
* atomic_set - set atomic variable
* @v: pointer of type atomic_t
* @i: required value
*
* Atomically sets the value of @v to @i. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_set(v,i) (((v)->counter) = (i))
/**
* atomic_inc - increment atomic variable
* @v: pointer of type atomic_t
*
* Atomically increments @v by 1. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
static __inline__ void atomic_inc(atomic_t *v)
{
__asm__ __volatile__(
"lock ; incl %0"
:"=m" (v->counter)
:"m" (v->counter));
}
/**
* atomic_dec - decrement atomic variable
* @v: pointer of type atomic_t
*
* Atomically decrements @v by 1. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
static __inline__ void atomic_dec(atomic_t *v)
{
__asm__ __volatile__(
"lock ; decl %0"
:"=m" (v->counter)
:"m" (v->counter));
}
#endif /* ARCH_SMP_ATOMIC_H */

View file

@ -0,0 +1,275 @@
#ifndef __ASM_MPSPEC_H
#define __ASM_MPSPEC_H
#ifdef HAVE_MP_TABLE
/*
* Structure definitions for SMP machines following the
* Intel Multiprocessing Specification 1.1 and 1.4.
*/
/*
* This tag identifies where the SMP configuration
* information is.
*/
#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
/*
* a maximum of 16 APICs with the current APIC ID architecture.
*/
#define MAX_APICS 16
#define SMP_FLOATING_TABLE_LEN sizeof(struct intel_mp_floating)
struct intel_mp_floating
{
char mpf_signature[4]; /* "_MP_" */
unsigned long mpf_physptr; /* Configuration table address */
unsigned char mpf_length; /* Our length (paragraphs) */
unsigned char mpf_specification;/* Specification version */
unsigned char mpf_checksum; /* Checksum (makes sum 0) */
unsigned char mpf_feature1; /* Standard or configuration ? */
unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */
unsigned char mpf_feature3; /* Unused (0) */
unsigned char mpf_feature4; /* Unused (0) */
unsigned char mpf_feature5; /* Unused (0) */
};
struct mp_config_table
{
char mpc_signature[4];
#define MPC_SIGNATURE "PCMP"
unsigned short mpc_length; /* Size of table */
char mpc_spec; /* 0x01 */
char mpc_checksum;
char mpc_oem[8];
char mpc_productid[12];
unsigned long mpc_oemptr; /* 0 if not present */
unsigned short mpc_oemsize; /* 0 if not present */
unsigned short mpc_entry_count;
unsigned long mpc_lapic; /* APIC address */
unsigned short mpe_length; /* Extended Table size */
unsigned char mpe_checksum; /* Extended Table checksum */
unsigned char reserved;
};
/* Followed by entries */
#define MP_PROCESSOR 0
#define MP_BUS 1
#define MP_IOAPIC 2
#define MP_INTSRC 3
#define MP_LINTSRC 4
struct mpc_config_processor
{
unsigned char mpc_type;
unsigned char mpc_apicid; /* Local APIC number */
unsigned char mpc_apicver; /* Its versions */
unsigned char mpc_cpuflag;
#define CPU_ENABLED 1 /* Processor is available */
#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */
unsigned long mpc_cpufeature;
#define CPU_STEPPING_MASK 0x0F
#define CPU_MODEL_MASK 0xF0
#define CPU_FAMILY_MASK 0xF00
unsigned long mpc_featureflag; /* CPUID feature value */
unsigned long mpc_reserved[2];
};
struct mpc_config_bus
{
unsigned char mpc_type;
unsigned char mpc_busid;
unsigned char mpc_bustype[6] __attribute((packed));
};
#define BUSTYPE_EISA "EISA"
#define BUSTYPE_ISA "ISA"
#define BUSTYPE_INTERN "INTERN" /* Internal BUS */
#define BUSTYPE_MCA "MCA"
#define BUSTYPE_VL "VL" /* Local bus */
#define BUSTYPE_PCI "PCI"
#define BUSTYPE_PCMCIA "PCMCIA"
struct mpc_config_ioapic
{
unsigned char mpc_type;
unsigned char mpc_apicid;
unsigned char mpc_apicver;
unsigned char mpc_flags;
#define MPC_APIC_USABLE 0x01
unsigned long mpc_apicaddr;
};
struct mpc_config_intsrc
{
unsigned char mpc_type;
unsigned char mpc_irqtype;
unsigned short mpc_irqflag;
unsigned char mpc_srcbus;
unsigned char mpc_srcbusirq;
unsigned char mpc_dstapic;
unsigned char mpc_dstirq;
};
enum mp_irq_source_types {
mp_INT = 0,
mp_NMI = 1,
mp_SMI = 2,
mp_ExtINT = 3
};
#define MP_IRQ_POLARITY_DEFAULT 0x0
#define MP_IRQ_POLARITY_HIGH 0x1
#define MP_IRQ_POLARITY_LOW 0x3
#define MP_IRQ_POLARITY_MASK 0x3
#define MP_IRQ_TRIGGER_DEFAULT 0x0
#define MP_IRQ_TRIGGER_EDGE 0x4
#define MP_IRQ_TRIGGER_LEVEL 0xc
#define MP_IRQ_TRIGGER_MASK 0xc
struct mpc_config_lintsrc
{
unsigned char mpc_type;
unsigned char mpc_irqtype;
unsigned short mpc_irqflag;
unsigned char mpc_srcbusid;
unsigned char mpc_srcbusirq;
unsigned char mpc_destapic;
#define MP_APIC_ALL 0xFF
unsigned char mpc_destapiclint;
};
/*
* Default configurations
*
* 1 2 CPU ISA 82489DX
* 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining
* 3 2 CPU EISA 82489DX
* 4 2 CPU MCA 82489DX
* 5 2 CPU ISA+PCI
* 6 2 CPU EISA+PCI
* 7 2 CPU MCA+PCI
*/
#define MAX_IRQ_SOURCES 128
#define MAX_MP_BUSSES 32
enum mp_bustype {
MP_BUS_ISA,
MP_BUS_EISA,
MP_BUS_PCI,
MP_BUS_MCA
};
/* Followed by entries */
#define MPE_SYSTEM_ADDRESS_SPACE 0x80
#define MPE_BUS_HIERARCHY 0x81
#define MPE_COMPATIBILITY_ADDRESS_SPACE 0x82
struct mp_exten_config {
unsigned char mpe_type;
unsigned char mpe_length;
};
typedef struct mp_exten_config *mpe_t;
struct mp_exten_system_address_space {
unsigned char mpe_type;
unsigned char mpe_length;
unsigned char mpe_busid;
unsigned char mpe_address_type;
#define ADDRESS_TYPE_IO 0
#define ADDRESS_TYPE_MEM 1
#define ADDRESS_TYPE_PREFETCH 2
unsigned int mpe_address_base_low;
unsigned int mpe_address_base_high;
unsigned int mpe_address_length_low;
unsigned int mpe_address_length_high;
};
struct mp_exten_bus_hierarchy {
unsigned char mpe_type;
unsigned char mpe_length;
unsigned char mpe_busid;
unsigned char mpe_bus_info;
#define BUS_SUBTRACTIVE_DECODE 1
unsigned char mpe_parent_busid;
unsigned char reserved[3];
};
struct mp_exten_compatibility_address_space {
unsigned char mpe_type;
unsigned char mpe_length;
unsigned char mpe_busid;
unsigned char mpe_address_modifier;
#define ADDRESS_RANGE_SUBTRACT 1
#define ADDRESS_RANGE_ADD 0
unsigned int mpe_range_list;
#define RANGE_LIST_IO_ISA 0
/* X100 - X3FF
* X500 - X7FF
* X900 - XBFF
* XD00 - XFFF
*/
#define RANGE_LIST_IO_VGA 1
/* X3B0 - X3BB
* X3C0 - X3DF
* X7B0 - X7BB
* X7C0 - X7DF
* XBB0 - XBBB
* XBC0 - XBDF
* XFB0 - XFBB
* XFC0 - XCDF
*/
};
/* Default local apic addr */
#define LAPIC_ADDR 0xFEE00000
void *smp_next_mpc_entry(struct mp_config_table *mc);
void *smp_next_mpe_entry(struct mp_config_table *mc);
void smp_write_processor(struct mp_config_table *mc,
unsigned char apicid, unsigned char apicver,
unsigned char cpuflag, unsigned int cpufeature,
unsigned int featureflag);
void smp_write_processors(struct mp_config_table *mc);
void smp_write_bus(struct mp_config_table *mc,
unsigned char id, unsigned char *bustype);
void smp_write_ioapic(struct mp_config_table *mc,
unsigned char id, unsigned char ver,
unsigned long apicaddr);
void smp_write_intsrc(struct mp_config_table *mc,
unsigned char irqtype, unsigned short irqflag,
unsigned char srcbus, unsigned char srcbusirq,
unsigned char dstapic, unsigned char dstirq);
void smp_write_lintsrc(struct mp_config_table *mc,
unsigned char irqtype, unsigned short irqflag,
unsigned char srcbusid, unsigned char srcbusirq,
unsigned char destapic, unsigned char destapiclint);
void smp_write_address_space(struct mp_config_table *mc,
unsigned char busid, unsigned char address_type,
unsigned int address_base_low, unsigned int address_base_high,
unsigned int address_length_low, unsigned int address_length_high);
void smp_write_bus_hierarchy(struct mp_config_table *mc,
unsigned char busid, unsigned char bus_info,
unsigned char parent_busid);
void smp_write_compatibility_address_space(struct mp_config_table *mc,
unsigned char busid, unsigned char address_modifier,
unsigned int range_list);
unsigned char smp_compute_checksum(void *v, int len);
void smp_write_floating_table(void *v);
void write_smp_table(void *v);
#else /* HAVE_MP_TABLE */
#define write_smp_table(v) do {} while(0)
#endif /* HAVE_MP_TABLE */
#endif

View file

@ -0,0 +1,57 @@
#ifndef ARCH_SMP_SPINLOCK_H
#define ARCH_SMP_SPINLOCK_H
/*
* Your basic SMP spinlocks, allowing only a single CPU anywhere
*/
typedef struct {
volatile unsigned int lock;
} spinlock_t;
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
/*
* Simple spin lock operations. There are two variants, one clears IRQ's
* on the local processor, one does not.
*
* We make no fairness assumptions. They have a cost.
*/
#define barrier() __asm__ __volatile__("": : :"memory")
#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) <= 0)
#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
#define spin_lock_string \
"\n1:\t" \
"lock ; decb %0\n\t" \
"js 2f\n" \
".section .text.lock,\"ax\"\n" \
"2:\t" \
"cmpb $0,%0\n\t" \
"rep;nop\n\t" \
"jle 2b\n\t" \
"jmp 1b\n" \
".previous"
/*
* This works. Despite all the confusion.
*/
#define spin_unlock_string \
"movb $1,%0"
static inline void spin_lock(spinlock_t *lock)
{
__asm__ __volatile__(
spin_lock_string
:"=m" (lock->lock) : : "memory");
}
static inline void spin_unlock(spinlock_t *lock)
{
__asm__ __volatile__(
spin_unlock_string
:"=m" (lock->lock) : : "memory");
}
#endif /* ARCH_SMP_SPINLOCK_H */

View file

@ -0,0 +1,55 @@
jmp cpu_reset_out
#ifdef DEBUG
cpu_reset_str: .string "cpu_reset\r\n";
cpu_size_set_str: .string "cpu memory size set\r\n";
#endif
__cpu_reset:
#ifdef DEBUG
TTYS0_TX_STRING($cpu_reset_str);
#endif /* DEBUG */
CALLSP(set_memory_size)
#ifdef DEBUG
TTYS0_TX_STRING($cpu_size_set_str);
#endif /* DEBUG */
#ifdef SMP
/* Test to see if we are the boot strap processor.
* If so the boot must be complete.
*/
movl $0x1b, %ecx
rdmsr
testl $0x100, %eax
jnz __reboot
/* Fixed mtrrs are enabled by the C code so if they
* aren't enabled yet we must be a secondary
* processor initializing in an SMP system.
*/
mov $MTRRdefType_MSR, %ecx
rdmsr
testl $0x400, %eax
jnz __reboot
/* set the stack pointer */
movl $_estack, %esp
movl $APIC_DEFAULT_BASE, %edi
movl APIC_ID(%edi), %eax
shrl $24, %eax
movl $STACK_SIZE, %ebx
mull %ebx
subl %eax, %esp
call EXT(secondary_cpu_init)
/* Fall through in case we somehow return */
#endif /* SMP */
__reboot:
movl $0xffffffff, %ebp
jmp __main
cpu_reset_out:

View file

@ -0,0 +1,65 @@
#ifdef HAVE_PIRQ_TABLE
#include <printk.h>
#include <pci.h>
#include <arch/pirq_routing.h>
#ifdef DEBUG
void check_pirq_routing_table(void)
{
const u8 *addr;
const struct irq_routing_table *rt;
int i;
u8 sum;
printk_info("Checking IRQ routing tables...");
rt = &intel_irq_routing_table;
addr = (u8 *)rt;
sum = 0;
for (i = 0; i < rt->size; i++)
sum += addr[i];
printk_debug("%s:%6d:%s() - irq_routing_table located at: 0x%p\n",
__FILE__, __LINE__, __FUNCTION__, addr);
sum = (unsigned char)(rt->checksum-sum);
if (sum != rt->checksum) {
printk_warning("%s:%6d:%s() - "
"checksum is: 0x%02x but should be: 0x%02x\n",
__FILE__, __LINE__, __FUNCTION__, rt->checksum, sum);
}
if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION ||
rt->size % 16 || rt->size < sizeof(struct irq_routing_table)) {
printk_warning("%s:%6d:%s() - "
"Interrupt Routing Table not valid\n",
__FILE__, __LINE__, __FUNCTION__);
return;
}
sum = 0;
for (i=0; i<rt->size; i++)
sum += addr[i];
if (sum) {
printk_warning("%s:%6d:%s() - "
"checksum error in irq routing table\n",
__FILE__, __LINE__, __FUNCTION__);
}
printk_info("done.\n");
}
#endif
#define RTABLE_DEST 0xf0000
void copy_pirq_routing_table(void)
{
printk_info("Copying IRQ routing tables...");
memcpy((char *) RTABLE_DEST, &intel_irq_routing_table, intel_irq_routing_table.size);
printk_info("done.\n");
}
#endif /* HAVE_PIRQ_TABLE */

3
src/arch/i386/smp/Config Normal file
View file

@ -0,0 +1,3 @@
object mpspec.o
object ioapic.o
object start_stop.o

137
src/arch/i386/smp/ioapic.c Normal file
View file

@ -0,0 +1,137 @@
#if defined(IOAPIC)
#include <arch/ioapic.h>
#include <printk.h>
/* TODO: this must move to chip/intel */
/* we have to do more than we thought. I assumed Linux would do all the
* interesting parts, and I was wrong.
*/
struct ioapicreg {
unsigned int reg;
unsigned int value_low, value_high;
};
struct ioapicreg ioapicregvalues[] = {
#define ALL (0xff << 24)
#define NONE (0)
#define DISABLED (1 << 16)
#define ENABLED (0 << 16)
#define TRIGGER_EDGE (0 << 15)
#define TRIGGER_LEVEL (1 << 15)
#define POLARITY_HIGH (0 << 13)
#define POLARITY_LOW (1 << 13)
#define PHYSICAL_DEST (0 << 11)
#define LOGICAL_DEST (1 << 11)
#define ExtINT (7 << 8)
#define NMI (4 << 8)
#define SMI (2 << 8)
#define INT (1 << 8)
#if 0 /* L440GX */
{0x00, DISABLED, NONE},
{0x01, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x59, ALL},
{0x02, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x51, ALL},
{0x03, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x61, NONE},
{0x04, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x69, ALL},
{0x05, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x71, NONE},
{0x06, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x79, NONE},
{0x07, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x81, NONE},
{0x08, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x89, ALL},
{0x09, DISABLED, NONE},
{0x0a, DISABLED, NONE},
{0x0b, DISABLED, NONE},
{0x0c, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x91, ALL},
{0x0d, DISABLED, NONE},
{0x0e, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x99, ALL},
{0x0f, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xa1, ALL},
{0x10, DISABLED, NONE},
{0x11, DISABLED, NONE},
{0x12, DISABLED, NONE},
{0x13, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0xa9, ALL},
{0x14, DISABLED, NONE},
{0x15, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0xb1, ALL},
{0x16, DISABLED, NONE},
{0x17, DISABLED, NONE}
#endif
#if 0 /* tyan guinness */
/* mask, trigger, polarity, destination, delivery, vector */
{0x00, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|ExtINT|0x0, ALL},
{0x01, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x1, ALL},
{0x02, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x0, ALL},
{0x03, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x3, ALL},
{0x04, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x4, ALL},
{0x05, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x5, ALL},
{0x06, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x6, ALL},
{0x07, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x7, ALL},
{0x08, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x8, ALL},
{0x09, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x9, ALL},
{0x0a, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xa, ALL},
{0x0b, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xb, ALL},
{0x0c, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xc, ALL},
{0x0d, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xd, ALL},
{0x0e, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xe, ALL},
{0x0f, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xf, ALL},
{0x10, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0x10, ALL},
{0x11, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0x11, ALL},
{0x12, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0x12, ALL},
{0x13, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0x13, ALL},
{0x14, DISABLED, NONE},
{0x14, DISABLED, NONE},
{0x15, DISABLED, NONE},
{0x16, DISABLED, NONE},
{0x17, DISABLED, NONE},
#endif
#if 1
/* mask, trigger, polarity, destination, delivery, vector */
{0x00, DISABLED, NONE},
{0x01, DISABLED, NONE},
{0x02, DISABLED, NONE},
{0x03, DISABLED, NONE},
{0x04, DISABLED, NONE},
{0x05, DISABLED, NONE},
{0x06, DISABLED, NONE},
{0x07, DISABLED, NONE},
{0x08, DISABLED, NONE},
{0x09, DISABLED, NONE},
{0x0a, DISABLED, NONE},
{0x0b, DISABLED, NONE},
{0x0c, DISABLED, NONE},
{0x0d, DISABLED, NONE},
{0x0e, DISABLED, NONE},
{0x0f, DISABLED, NONE},
{0x10, DISABLED, NONE},
{0x11, DISABLED, NONE},
{0x12, DISABLED, NONE},
{0x13, DISABLED, NONE},
{0x14, DISABLED, NONE},
{0x14, DISABLED, NONE},
{0x15, DISABLED, NONE},
{0x16, DISABLED, NONE},
{0x17, DISABLED, NONE},
#endif
};
void setup_ioapic(void)
{
int i;
unsigned long value_low, value_high;
unsigned long nvram = 0xfec00000;
volatile unsigned long *l;
struct ioapicreg *a = ioapicregvalues;
l = (unsigned long *) nvram;
for (i = 0; i < sizeof(ioapicregvalues) / sizeof(ioapicregvalues[0]);
i++, a++) {
l[0] = (a->reg * 2) + 0x10;
l[4] = a->value_low;
value_low = l[4];
l[0] = (a->reg *2) + 0x11;
l[4] = a->value_high;
value_high = l[4];
if ((i==0) && (value_low == 0xffffffff)) {
printk_warning("IO APIC not responding.\n");
return;
}
printk_spew("for IRQ, reg 0x%08x value 0x%08x 0x%08x\n",
a->reg, a->value_low, a->value_high);
}
}
#endif /* IOAPIC */

243
src/arch/i386/smp/mpspec.c Normal file
View file

@ -0,0 +1,243 @@
#ifdef HAVE_MP_TABLE
#ifndef lint
static char rcsid[] = "$Id$";
#endif
#include <smp/start_stop.h>
#include <arch/smp/mpspec.h>
#include <string.h>
#include <cpu/p5/cpuid.h>
#include <cpu/p6/apic.h>
#include <printk.h>
unsigned char smp_compute_checksum(void *v, int len)
{
unsigned char *bytes;
unsigned char checksum;
int i;
bytes = v;
checksum = 0;
for(i = 0; i < len; i++) {
checksum -= bytes[i];
}
return checksum;
}
void smp_write_floating_table(void *v)
{
struct intel_mp_floating *mf;
mf = v;
mf->mpf_signature[0] = '_';
mf->mpf_signature[1] = 'M';
mf->mpf_signature[2] = 'P';
mf->mpf_signature[3] = '_';
mf->mpf_physptr = (unsigned long)(((char *)v) + SMP_FLOATING_TABLE_LEN);
mf->mpf_length = 1;
mf->mpf_specification = 4;
mf->mpf_checksum = 0;
mf->mpf_feature1 = 0;
mf->mpf_feature2 = 0;
mf->mpf_feature3 = 0;
mf->mpf_feature4 = 0;
mf->mpf_feature5 = 0;
mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16);
}
void *smp_next_mpc_entry(struct mp_config_table *mc)
{
void *v;
v = (void *)(((char *)mc) + mc->mpc_length);
return v;
}
static void smp_add_mpc_entry(struct mp_config_table *mc, unsigned length)
{
mc->mpc_length += length;
mc->mpc_entry_count++;
}
void *smp_next_mpe_entry(struct mp_config_table *mc)
{
void *v;
v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length);
return v;
}
static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe)
{
mc->mpe_length += mpe->mpe_length;
}
void smp_write_processor(struct mp_config_table *mc,
unsigned char apicid, unsigned char apicver,
unsigned char cpuflag, unsigned int cpufeature,
unsigned int featureflag)
{
struct mpc_config_processor *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_PROCESSOR;
mpc->mpc_apicid = apicid;
mpc->mpc_apicver = apicver;
mpc->mpc_cpuflag = cpuflag;
mpc->mpc_cpufeature = cpufeature;
mpc->mpc_featureflag = featureflag;
smp_add_mpc_entry(mc, sizeof(*mpc));
}
/* If we assume a symmetric processor configuration we can
* get all of the information we need to write the processor
* entry from the bootstrap processor.
* Plus I don't think linux really even cares.
* Having the proper apicid's in the table so the non-bootstrap
* processors can be woken up should be enough.
*/
void smp_write_processors(struct mp_config_table *mc)
{
int i;
int processor_id;
unsigned apic_version;
unsigned cpu_features;
unsigned cpu_feature_flags;
int eax, ebx, ecx, edx;
processor_id = this_processors_id();
apic_version = apic_read(APIC_LVR) & 0xff;
cpuid(1, &eax, &ebx, &ecx, &edx);
cpu_features = eax;
cpu_feature_flags = edx;
for(i = 0; i < MAX_CPUS; i++) {
smp_write_processor(mc, i, apic_version,
((processor_id == i)? CPU_BOOTPROCESSOR:0) | CPU_ENABLED,
cpu_features, cpu_feature_flags
);
}
}
void smp_write_bus(struct mp_config_table *mc,
unsigned char id, unsigned char *bustype)
{
struct mpc_config_bus *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_BUS;
mpc->mpc_busid = id;
memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype));
smp_add_mpc_entry(mc, sizeof(*mpc));
}
void smp_write_ioapic(struct mp_config_table *mc,
unsigned char id, unsigned char ver,
unsigned long apicaddr)
{
struct mpc_config_ioapic *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_IOAPIC;
mpc->mpc_apicid = id;
mpc->mpc_apicver = ver;
mpc->mpc_flags = MPC_APIC_USABLE;
mpc->mpc_apicaddr = apicaddr;
smp_add_mpc_entry(mc, sizeof(*mpc));
}
void smp_write_intsrc(struct mp_config_table *mc,
unsigned char irqtype, unsigned short irqflag,
unsigned char srcbus, unsigned char srcbusirq,
unsigned char dstapic, unsigned char dstirq)
{
struct mpc_config_intsrc *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_INTSRC;
mpc->mpc_irqtype = irqtype;
mpc->mpc_irqflag = irqflag;
mpc->mpc_srcbus = srcbus;
mpc->mpc_srcbusirq = srcbusirq;
mpc->mpc_dstapic = dstapic;
mpc->mpc_dstirq = dstirq;
smp_add_mpc_entry(mc, sizeof(*mpc));
}
void smp_write_lintsrc(struct mp_config_table *mc,
unsigned char irqtype, unsigned short irqflag,
unsigned char srcbusid, unsigned char srcbusirq,
unsigned char destapic, unsigned char destapiclint)
{
struct mpc_config_lintsrc *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_LINTSRC;
mpc->mpc_irqtype = irqtype;
mpc->mpc_irqflag = irqflag;
mpc->mpc_srcbusid = srcbusid;
mpc->mpc_srcbusirq = srcbusirq;
mpc->mpc_destapic = destapic;
mpc->mpc_destapiclint = destapiclint;
smp_add_mpc_entry(mc, sizeof(*mpc));
}
void smp_write_address_space(struct mp_config_table *mc,
unsigned char busid, unsigned char address_type,
unsigned int address_base_low, unsigned int address_base_high,
unsigned int address_length_low, unsigned int address_length_high)
{
struct mp_exten_system_address_space *mpe;
mpe = smp_next_mpe_entry(mc);
memset(mpe, '\0', sizeof(*mpe));
mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE;
mpe->mpe_length = sizeof(*mpe);
mpe->mpe_busid = busid;
mpe->mpe_address_type = address_type;
mpe->mpe_address_base_low = address_base_low;
mpe->mpe_address_base_high = address_base_high;
mpe->mpe_address_length_low = address_length_low;
mpe->mpe_address_length_high = address_length_high;
smp_add_mpe_entry(mc, (mpe_t)mpe);
}
void smp_write_bus_hierarchy(struct mp_config_table *mc,
unsigned char busid, unsigned char bus_info,
unsigned char parent_busid)
{
struct mp_exten_bus_hierarchy *mpe;
mpe = smp_next_mpe_entry(mc);
memset(mpe, '\0', sizeof(*mpe));
mpe->mpe_type = MPE_BUS_HIERARCHY;
mpe->mpe_length = sizeof(*mpe);
mpe->mpe_busid = busid;
mpe->mpe_bus_info = bus_info;
mpe->mpe_parent_busid = parent_busid;
smp_add_mpe_entry(mc, (mpe_t)mpe);
}
void smp_write_compatibility_address_space(struct mp_config_table *mc,
unsigned char busid, unsigned char address_modifier,
unsigned int range_list)
{
struct mp_exten_compatibility_address_space *mpe;
mpe = smp_next_mpe_entry(mc);
memset(mpe, '\0', sizeof(*mpe));
mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE;
mpe->mpe_length = sizeof(*mpe);
mpe->mpe_busid = busid;
mpe->mpe_address_modifier = address_modifier;
mpe->mpe_range_list = range_list;
smp_add_mpe_entry(mc, (mpe_t)mpe);
}
#if 0
/* memcpy standard block */
const static char smpblock[] =
{0x5F, 0x4D, 0x50, 0x5F, 0x00, 0x00, 0x00,
0x00, 0x01, 0x04, 0x9B, 0x05, 0x00, 0x00, 0x00, 0x00
};
void write_smp_table(void *v)
{
memcpy(v, smpblock, sizeof(smpblock));
}
#endif /* 0 */
#endif /* HAVE_MP_TABLE */

View file

@ -0,0 +1,194 @@
#include <smp/start_stop.h>
#include <cpu/p6/apic.h>
#include <delay.h>
static inline void hlt(void)
{
asm("hlt");
return;
}
int this_processors_id(void)
{
return apic_read(APIC_ID) >> 24;
}
void stop_cpu(int apicid)
{
int timeout;
unsigned long send_status;
/* send an APIC INIT to myself */
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
/* wait for the ipi send to finish */
printk_spew("Waiting for send to finish...\n");
timeout = 0;
do {
printk_spew("+");
udelay(100);
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
if (timeout >= 1000) {
printk_spew("timed out\n");
}
mdelay(10);
printk_spew("Deasserting INIT.\n");
/* Deassert the APIC INIT */
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
printk_spew("Waiting for send to finish...\n");
timeout = 0;
do {
printk_spew("+");
udelay(100);
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
if (timeout >= 1000) {
printk_debug("timed out\n");
}
while(1) {
hlt();
}
}
void start_cpu(int apicid)
{
int timeout;
unsigned long send_status, accept_status, start_eip;
int j, num_starts, maxlvt;
/*
* Starting actual IPI sequence...
*/
printk_spew("Asserting INIT.\n");
/*
* Turn INIT on target chip
*/
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
/*
* Send IPI
*/
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
| APIC_DM_INIT);
printk_spew("Waiting for send to finish...\n");
timeout = 0;
do {
printk_spew("+");
udelay(100);
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
if (timeout >= 1000) {
printk_spew("timed out\n");
}
mdelay(10);
printk_spew("Deasserting INIT.\n");
/* Target chip */
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
/* Send IPI */
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
printk_spew("Waiting for send to finish...\n");
timeout = 0;
do {
printk_spew("+");
udelay(100);
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
if (timeout >= 1000) {
printk_spew("timed out\n");
}
/* FIXME start_eip should be more flexible! */
start_eip = 0xf0000;
printk_spew("start eip=0x%08lx\n", start_eip);
num_starts = 2;
/*
* Run STARTUP IPI loop.
*/
printk_spew("#startup loops: %d.\n", num_starts);
maxlvt = 4;
for (j = 1; j <= num_starts; j++) {
printk_spew("Sending STARTUP #%d.\n",j);
apic_read_around(APIC_SPIV);
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);
printk_spew("After apic_write.\n");
/*
* STARTUP IPI
*/
/* Target chip */
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
/* Boot on the stack */
/* Kick the second */
apic_write_around(APIC_ICR, APIC_DM_STARTUP
| (start_eip >> 12));
/*
* Give the other CPU some time to accept the IPI.
*/
udelay(300);
printk_spew("Startup point 1.\n");
printk_spew("Waiting for send to finish...\n");
timeout = 0;
do {
printk_spew("+");
udelay(100);
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
/*
* Give the other CPU some time to accept the IPI.
*/
udelay(200);
/*
* Due to the Pentium erratum 3AP.
*/
if (maxlvt > 3) {
apic_read_around(APIC_SPIV);
apic_write(APIC_ESR, 0);
}
accept_status = (apic_read(APIC_ESR) & 0xEF);
if (send_status || accept_status)
break;
}
printk_spew("After Startup.\n");
if (send_status)
printk_warning("APIC never delivered???\n");
if (accept_status)
printk_warning("APIC delivery error (%lx).\n", accept_status);
}
void startup_other_cpus(void)
{
int apicid = this_processors_id();
int i;
/* Assume the cpus are densly packed by apicid */
for(i = 0; i < MAX_CPUS; i++) {
if (i == apicid ) {
continue;
}
start_cpu(i);
}
}

91
src/cpu/k7/earlymtrr.inc Normal file
View file

@ -0,0 +1,91 @@
#include <cpu/k7/mtrr.h>
/* The fixed and variable MTRRs are powered-up with random values, clear them to
* MTRR_TYPE_UNCACHABLE for safty reason
*/
earlymtrr_start:
xorl %eax, %eax # clear %eax and %edx
xorl %edx, %edx #
movl $fixed_mtrr_msr, %esi
clear_fixed_var_mtrr:
lodsl (%esi), %eax
testl %eax, %eax
jz clear_fixed_var_mtrr_out
movl %eax, %ecx
xorl %eax, %eax
wrmsr
jmp clear_fixed_var_mtrr
clear_fixed_var_mtrr_out:
set_var_mtrr:
/* enable caching for 0 - 128MB using variable mtrr */
movl $0x200, %ecx
rdmsr
andl $0xfffffff0, %edx
orl $0x00000000, %edx
andl $0x00000f00, %eax
orl $0x00000006, %eax
wrmsr
movl $0x201, %ecx
rdmsr
andl $0xfffffff0, %edx
orl $0x0000000f, %edx
andl $0x000007ff, %eax
orl $0xf0000800, %eax
wrmsr
#if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE)
/* enable write protect caching so we can do execute in place
* on the flash rom.
*/
movl $0x202, %ecx
xorl %edx, %edx
movl $(XIP_ROM_BASE | 0x005), %eax
wrmsr
movl $0x203, %ecx
movl $0x0000000f, %edx
movl $(~(XIP_ROM_SIZE - 1) | 0x800), %eax
wrmsr
#endif /* XIP_ROM_SIZE && XIP_ROM_BASE */
enable_mtrr:
/* Set the default memory type and enable fixed and variable MTRRs */
movl $0x2ff, %ecx
xorl %edx, %edx
/* Enable Variable MTRRs */
movl $0x00000800, %eax
wrmsr
/* Enable the MTRRs in SYSCFG */
#if USE_AMD_NDA_CODE
#endif /* USE_AMD_NDA_CODE */
/* enable cache */
movl %cr0, %eax
andl $0x9fffffff,%eax
movl %eax, %cr0
jmp earlymtrr_end
fixed_mtrr_msr:
.long 0x250, 0x258, 0x259
.long 0x268, 0x269, 0x26A
.long 0x26B, 0x26C, 0x26D
.long 0x26E, 0x26F
var_mtrr_msr:
.long 0x200, 0x201, 0x202, 0x203
.long 0x204, 0x205, 0x206, 0x207
.long 0x208, 0x209, 0x20A, 0x20B
.long 0x20C, 0x20D, 0x20E, 0x20F
#if USE_AMD_NDA_CODE
#endif /* USE_AMD_NDA_CODE */
.long 0x000 /* NULL, end of table */
earlymtrr_end:

View file

@ -0,0 +1,17 @@
#ifndef CPU_CPUFIXUP_H
#define CPU_CPUFIXUP_H
#include <cpu/k7/cpufixup.h>
#include <cpu/p6/cpufixup.h>
#ifdef CPU_FIXUP
# if defined(k7)
# define cpufixup(totalram) k7_cpufixup(totalram)
# elif defined(i686)
# define cpufixup(totalram) p6_cpufixup(totalram)
# endif
#else
# define cpu_fixup(totalram) do {} while(0)
#endif
#endif /* CPU_CPUFIXUP_H */

View file

@ -0,0 +1,6 @@
#ifndef CPU_K7_CPUFIXUP_H
#define CPU_K7_CPUFIXUP_H
void k7_cpufixup(unsigned long totalram);
#endif /* CPU_K7_CPUFIXUP_H */

View file

@ -0,0 +1,9 @@
#ifndef CPU_K7_MTRR_H
#define CPU_K7_MTRR_H
#include <cpu/p6/mtrr.h>
# if USE_AMD_NDA_CODE
# endif /* USE_AMD_NDA_CODE */
#endif /* CPU_K7_MTRR_H */

View file

@ -0,0 +1,14 @@
#ifndef CPU_L2_CACHE_H
#define CPU_L2_CACHE_H
#include <cpu/p6/l2_cache.h>
#ifdef CONFIGURE_L2_CACHE
# if defined(i686)
# define configure_l2_cache() p6_configure_l2_cache()
# endif
#else
# define configure_l2_cache() do {} while(0)
#endif
#endif /* CPU_L2_CACHE_H */

176
src/include/cpu/p6/apic.h Normal file
View file

@ -0,0 +1,176 @@
#ifndef APIC_H
#define APIC_H
#define APIC_BASE_MSR 0x1B
#define APIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8)
#define APIC_BASE_MSR_ENABLE (1 << 11)
#define APIC_BASE_MSR_ADDR_MASK 0xFFFFF000
#define APIC_DEFAULT_BASE 0xfee00000
#define APIC_ID 0x020
#define APIC_LVR 0x030
#define APIC_ARBID 0x090
#define APIC_RRR 0x0C0
#define APIC_SVR 0x0f0
#define APIC_SPIV 0x0f0
#define APIC_SPIV_ENABLE 0x100
#define APIC_ESR 0x280
#define APIC_ESR_SEND_CS 0x00001
#define APIC_ESR_RECV_CS 0x00002
#define APIC_ESR_SEND_ACC 0x00004
#define APIC_ESR_RECV_ACC 0x00008
#define APIC_ESR_SENDILL 0x00020
#define APIC_ESR_RECVILL 0x00040
#define APIC_ESR_ILLREGA 0x00080
#define APIC_ICR 0x300
#define APIC_DEST_SELF 0x40000
#define APIC_DEST_ALLINC 0x80000
#define APIC_DEST_ALLBUT 0xC0000
#define APIC_ICR_RR_MASK 0x30000
#define APIC_ICR_RR_INVALID 0x00000
#define APIC_ICR_RR_INPROG 0x10000
#define APIC_ICR_RR_VALID 0x20000
#define APIC_INT_LEVELTRIG 0x08000
#define APIC_INT_ASSERT 0x04000
#define APIC_ICR_BUSY 0x01000
#define APIC_DEST_LOGICAL 0x00800
#define APIC_DM_FIXED 0x00000
#define APIC_DM_LOWEST 0x00100
#define APIC_DM_SMI 0x00200
#define APIC_DM_REMRD 0x00300
#define APIC_DM_NMI 0x00400
#define APIC_DM_INIT 0x00500
#define APIC_DM_STARTUP 0x00600
#define APIC_DM_EXTINT 0x00700
#define APIC_VECTOR_MASK 0x000FF
#define APIC_ICR2 0x310
#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF)
#define SET_APIC_DEST_FIELD(x) ((x)<<24)
#define APIC_LVTT 0x320
#define APIC_LVTPC 0x340
#define APIC_LVT0 0x350
#define APIC_LVT_TIMER_BASE_MASK (0x3<<18)
#define GET_APIC_TIMER_BASE(x) (((x)>>18)&0x3)
#define SET_APIC_TIMER_BASE(x) (((x)<<18))
#define APIC_TIMER_BASE_CLKIN 0x0
#define APIC_TIMER_BASE_TMBASE 0x1
#define APIC_TIMER_BASE_DIV 0x2
#define APIC_LVT_TIMER_PERIODIC (1<<17)
#define APIC_LVT_MASKED (1<<16)
#define APIC_LVT_LEVEL_TRIGGER (1<<15)
#define APIC_LVT_REMOTE_IRR (1<<14)
#define APIC_INPUT_POLARITY (1<<13)
#define APIC_SEND_PENDING (1<<12)
#define APIC_LVT_RESERVED_1 (1<<11)
#define APIC_DELIVERY_MODE_MASK (7<<8)
#define APIC_DELIVERY_MODE_FIXED (0<<8)
#define APIC_DELIVERY_MODE_NMI (4<<8)
#define APIC_DELIVERY_MODE_EXTINT (7<<8)
#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7)
#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8))
#define APIC_MODE_FIXED 0x0
#define APIC_MODE_NMI 0x4
#define APIC_MODE_EXINT 0x7
#define APIC_LVT1 0x360
#define APIC_LVTERR 0x370
#if !defined(ASSEMBLY)
#include <printk.h>
#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))
/*
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway
* Note 2: xchg has side effect, so that attribute volatile is necessary,
* but generally the primitive is invalid, *ptr is output argument. --ANK
*/
static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
{
switch (size) {
case 1:
__asm__ __volatile__("xchgb %b0,%1"
:"=q" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
case 2:
__asm__ __volatile__("xchgw %w0,%1"
:"=r" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
case 4:
__asm__ __volatile__("xchgl %0,%1"
:"=r" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
}
return x;
}
static inline unsigned long apic_read(unsigned long reg)
{
return *((volatile unsigned long *)(APIC_DEFAULT_BASE+reg));
}
extern inline void apic_write_atomic(unsigned long reg, unsigned long v)
{
xchg((volatile unsigned long *)(APIC_DEFAULT_BASE+reg), v);
}
static inline void apic_write(unsigned long reg, unsigned long v)
{
*((volatile unsigned long *)(APIC_DEFAULT_BASE+reg)) = v;
}
static inline void apic_wait_icr_idle(void)
{
do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY );
}
#ifdef CONFIG_X86_GOOD_APIC
# define FORCE_READ_AROUND_WRITE 0
# define apic_read_around(x)
# define apic_write_around(x,y) apic_write((x),(y))
#else
# define FORCE_READ_AROUND_WRITE 1
# define apic_read_around(x) apic_read(x)
# define apic_write_around(x,y) apic_write_atomic((x),(y))
#endif
static inline unsigned long apic_remote_read(int apicid, int reg)
{
int timeout;
unsigned long status, result;
apic_wait_icr_idle();
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write_around(APIC_ICR, APIC_DM_REMRD | (reg >> 4));
timeout = 0;
do {
#if 0
udelay(100);
#endif
status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
} while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
result = -1;
if (status == APIC_ICR_RR_VALID) {
result = apic_read(APIC_RRR);
}
else {
printk_err("remote apic read failed\n");
}
return result;
}
#endif /* ASSEMBLY */
#endif /* APIC_H */

View file

@ -0,0 +1,10 @@
#ifndef CPU_P6_CPUFIXUP_H
#define CPU_P6_CPUFIXUP_H
#ifdef UPDATE_MICROCODE
#define CPU_FIXUP
#endif
void p6_cpufixup(unsigned long totalram);
#endif /* CPU_P6_CPUFIXUP_H */

7
src/include/delay.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef DELAY_H
#define DELAY_H
void udelay(int usecs);
void mdelay(int msecs);
#endif /* DELAY_H */

10
src/include/part/floppy.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef PART_FLOPPY_H
#define PART_FLOPPY_H
#ifdef MUST_ENABLE_FLOPPY
void enable_floppy(void);
#else
# define enable_floppy() do {} while(0)
#endif
#endif /* PART_FLOPPY_H */

View file

@ -0,0 +1,10 @@
#ifndef PART_FRAMEBUFFER_H
#define PART_FRAMEBUFFER_H
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on(void)
#else
# define framebuffer_on() do {} while(0)
#endif /* HAVE_FRAMEBUFFER */
#endif /* PART_FRAMEBUFFER_H */

View file

@ -0,0 +1,11 @@
#ifndef PART_HARD_RESET_H
#define PART_HARD_RESET_H
#ifdef HAVE_HARD_RESET
void hard_reset(void);
#else
#define hard_reset() do {} while(0)
#endif
#endif

View file

@ -0,0 +1,10 @@
#ifndef PART_KEYBOARD_H
#define KEYBOARD_H
#ifndef NO_KEYBOARD
void keyboard_on(void);
#else
# define keyboard_on() do {} while(0)
#endif
#endif /* PART_KEYBOARD_H */

View file

@ -0,0 +1,12 @@
#ifndef PART_MAINBOARD_H
#define PART_MAINBOARD_H
void mainboard_fixup(void);
#ifdef FINAL_MAINBOARD_FIXUP
void final_mainboard_fixup(void);
#else
# define final_mainboard_fixup() do {} while(0)
#endif /* FINAL_MAINBOARD_FIXUP */
#endif /* PART_MAINBOARD_H */

7
src/include/part/nvram.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef PART_NVRAM_H
#define PART_NVRAM_H
/* Turn on full access to the flash chip */
void nvram_on(void);
#endif /* PART_NVRAM_H */

View file

@ -0,0 +1,6 @@
#ifndef PART_SIZERAM_H
#define PART_SIZERAM_H
unsigned long sizeram(void);
#endif /* PART_SIZERAM_H */

11
src/include/pc80/i8259.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef PC80_I8259
#define PC80_I8259
#ifdef I8259
void setup_i8259(void);
#else
#define setup_i8259() do {} while(0)
#endif
#endif

View file

@ -1 +1,6 @@
#ifndef PC80_KEYBOARD_H
#define PC80_KEYBOARD_H
void pc_keyboard_init(void);
#endif /* PC80_KEYBOARD_H */

53
src/include/smp/atomic.h Normal file
View file

@ -0,0 +1,53 @@
#ifndef SMP_ATOMIC_H
#define SMP_ATOMIC_H
#ifdef SMP
#include <arch/smp/atomic.h>
#else
typedef struct { int counter } atomic_t;
#define ATOMIC_INIT(i) { (i) }
/**
* atomic_read - read atomic variable
* @v: pointer of type atomic_t
*
* Atomically reads the value of @v. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_read(v) ((v)->counter)
/**
* atomic_set - set atomic variable
* @v: pointer of type atomic_t
* @i: required value
*
* Atomically sets the value of @v to @i. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_set(v,i) (((v)->counter) = (i))
/**
* atomic_inc - increment atomic variable
* @v: pointer of type atomic_t
*
* Atomically increments @v by 1. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_inc(v) (((v)->counter)++)
/**
* atomic_dec - decrement atomic variable
* @v: pointer of type atomic_t
*
* Atomically decrements @v by 1. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_inc(v) (((v)->counter)--)
#endif /* SMP */
#endif /* SMP_ATOMIC_H */

View file

@ -0,0 +1,24 @@
#ifndef SMP_SPINLOCK_H
#define SMP_SPINLOCK_H
#ifdef SMP
#include <arch/smp/spinlock.h>
#else /* !SMP */
/* Most GCC versions have a nasty bug with empty initializers */
#if (__GNUC__ > 2)
typedef struct { } spinlock_t;
#define SPIN_LOCK_UNLOCKED (spinlock_t) { }
#else
typedef struct { int gcc_is_buggy; } spinlock_t;
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
#endif
#define barrier() do {} while(0)
#define spin_is_locked(lock) 0
#define spin_unlock_wait(lock) do {} while(0)
#define spin_lock(lock) do {} while(0)
#define spin_unlock(lock) do {} while(0)
#endif
#endif /* SMP_SPINLOCK_H */

View file

@ -0,0 +1,15 @@
#ifndef SMP_START_STOP_H
#define SMP_START_STOP_H
#ifdef SMP
#include <smp/atomic.h>
int this_processors_id(void);
void stop_cpu(int processor_id);
void start_cpu(int processor_id);
void startup_other_cpus(void);
#else
#define this_processors_id() 0
#define startup_other_cpus() do {} while(0)
#endif
#endif /* SMP_START_STOP_H */

63
src/lib/delay.c Normal file
View file

@ -0,0 +1,63 @@
#include <delay.h>
#include <arch/io.h>
/* Ports for the 8254 timer chip */
#define TIMER2_PORT 0x42
#define TIMER_MODE_PORT 0x43
/* Meaning of the mode bits */
#define TIMER0_SEL 0x00
#define TIMER1_SEL 0x40
#define TIMER2_SEL 0x80
#define READBACK_SEL 0xC0
#define LATCH_COUNT 0x00
#define LOBYTE_ACCESS 0x10
#define HIBYTE_ACCESS 0x20
#define WORD_ACCESS 0x30
#define MODE0 0x00
#define MODE1 0x02
#define MODE2 0x04
#define MODE3 0x06
#define MODE4 0x08
#define MODE5 0x0A
#define BINARY_COUNT 0x00
#define BCD_COUNT 0x01
/* Timers tick over at this rate */
#define TICKS_PER_MS 1193
/* Parallel Peripheral Controller Port B */
#define PPC_PORTB 0x61
/* Meaning of the port bits */
#define PPCB_T2OUT 0x20 /* Bit 5 */
#define PPCB_SPKR 0x02 /* Bit 1 */
#define PPCB_T2GATE 0x01 /* Bit 0 */
static void load_timer2(unsigned int ticks)
{
/* Set up the timer gate, turn off the speaker */
outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB);
outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT);
outb(ticks & 0xFF, TIMER2_PORT);
outb(ticks >> 8, TIMER2_PORT);
}
void udelay(int usecs)
{
load_timer2((usecs*TICKS_PER_MS)/1000);
while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0)
;
}
void mdelay(int msecs)
{
int i;
for(i = 0; i < msecs; i++) {
udelay(1000);
}
}

View file

@ -0,0 +1,137 @@
#include <cpu/p6/mpspec.h>
#include <string.h>
void smp_write_config_table(void *v)
{
int ioapicid = 0; // JAMES_HACK
static const char sig[4] = "PCMP";
static const char oem[8] = "LNXI ";
static const char productid[12] = "L440GX ";
struct mp_config_table *mc;
mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);
memset(mc, 0, sizeof(*mc));
memcpy(mc->mpc_signature, sig, sizeof(sig));
mc->mpc_length = sizeof(*mc); /* initially just the header */
mc->mpc_spec = 0x04;
mc->mpc_checksum = 0; /* not yet computed */
memcpy(mc->mpc_oem, oem, sizeof(oem));
memcpy(mc->mpc_productid, productid, sizeof(productid));
mc->mpc_oemptr = 0;
mc->mpc_oemsize = 0;
mc->mpc_entry_count = 0; /* No entries yet... */
mc->mpc_lapic = LAPIC_ADDR;
mc->mpe_length = 0;
mc->mpe_checksum = 0;
mc->reserved = 0;
#ifndef JAMES_HACK
smp_write_processor(mc, 0x01, 0x11,
CPU_ENABLED | CPU_BOOTPROCESSOR, 0x00000683, 0x0387fbff);
#else
printk("James: Setting up 2 proc. SMP table");
smp_write_processor(mc, 0x1, 0x11,
CPU_ENABLED | CPU_BOOTPROCESSOR, 0x00000683, 0x0387fbff);
smp_write_processor(mc, 0x0, 0x11,
CPU_ENABLED, 0x00000683, 0x0387fbff);
ioapicid = 2;
#endif
smp_write_bus(mc, 0, "PCI ");
smp_write_bus(mc, 1, "PCI ");
smp_write_bus(mc, 2, "PCI ");
smp_write_bus(mc, 3, "ISA ");
smp_write_ioapic(mc, ioapicid, 0x11, 0xfec00000);
/* ISA backward compatibility interrupts */
smp_write_intsrc(mc, mp_ExtINT, 0x05, 0x03, 0x00, ioapicid, 0x00);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x01, ioapicid, 0x01);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x00, ioapicid, 0x02);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x03, ioapicid, 0x03);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x04, ioapicid, 0x03);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x04, ioapicid, 0x04);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x06, ioapicid, 0x06);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x07, ioapicid, 0x07);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x08, ioapicid, 0x08);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x0c, ioapicid, 0x0c);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x0d, ioapicid, 0x0d);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x0e, ioapicid, 0x0e);
smp_write_intsrc(mc, mp_INT, 0x05, 0x03, 0x0f, ioapicid, 0x0f);
/* On bus 0 device 1 is the 440GX AGP/PCI bridge to bus 1 */
/* On bus 1 device f is a DEC PCI bridge to bus 2 */
/* Onboard pci devices */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x30, ioapicid, 0x13); /* onboard SCSI */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x38, ioapicid, 0x15); /* onboard NIC */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x4b, ioapicid, 0x15); /* onboard PIIX4 */
/* PCI card slots */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x02, 0x1c, ioapicid, 0x17); /* slot 6 A */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x02, 0x1d, ioapicid, 0x14); /* slot 6 B */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x02, 0x1e, ioapicid, 0x15); /* slot 6 C */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x02, 0x1f, ioapicid, 0x16); /* slot 6 D */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x02, 0x10, ioapicid, 0x14); /* slot 5 A */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x02, 0x11, ioapicid, 0x15); /* slot 5 B */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x02, 0x12, ioapicid, 0x16); /* slot 5 C */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x02, 0x13, ioapicid, 0x17); /* slot 5 D */
/* 64bit slot */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x24, ioapicid, 0x13); /* slot 4 A */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x25, ioapicid, 0x15); /* slot 4 B */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x26, ioapicid, 0x16); /* slot 4 C */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x27, ioapicid, 0x17); /* slot 4 D */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x2c, ioapicid, 0x12); /* slot 3 A */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x2d, ioapicid, 0x17); /* slot 3 B */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x2e, ioapicid, 0x15); /* slot 3 C */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x2f, ioapicid, 0x16); /* slot 3 D */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x34, ioapicid, 0x11); /* slot 2 A */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x35, ioapicid, 0x16); /* slot 2 B */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x36, ioapicid, 0x17); /* slot 2 C */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x37, ioapicid, 0x15); /* slot 2 D */
/* If this slot hadn't been removed I'd know it's PCI address,
* I'm guessing it's slot 0x0f (i.e. 0x3c >> 2) but I haven't
* confirmed that.
*/
/* Slot one is the slot farthest from the processor */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x3c, ioapicid, 0x10); /* slot 1 A */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x3d, ioapicid, 0x15); /* slot 1 B */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x3e, ioapicid, 0x16); /* slot 1 C */
smp_write_intsrc(mc, mp_INT, 0x0f, 0x00, 0x3f, ioapicid, 0x17); /* slot 1 D */
/* Standard local interrupt assignments */
smp_write_lintsrc(mc, mp_ExtINT, 0x05, 0x03, 0x00, MP_APIC_ALL, 0x00);
smp_write_lintsrc(mc, mp_NMI, 0x05, 0x00, 0x00, MP_APIC_ALL, 0x01);
/* The following information in the extension section linux doesn't currnetly need
* and has just been copied from the bios for now.
*/
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_IO, 0x00000000, 0, 0x00010000, 0);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x08000000, 0, 0xee000000, 0);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_PREFETCH, 0xf6000000, 0, 0x06000000, 0);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0xfc000000, 0, 0x02e00000, 0);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0xfef00000, 0, 0x01100000, 0);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000a0000, 0, 0x00200000, 0);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000d4000, 0, 0x00014000, 0);
smp_write_bus_hierarchy(mc, 0x03, BUS_SUBTRACTIVE_DECODE, 0x00);
smp_write_compatibility_address_space(mc, 0x00, ADDRESS_RANGE_ADD, RANGE_LIST_IO_ISA);
smp_write_compatibility_address_space(mc, 0x00, ADDRESS_RANGE_ADD, RANGE_LIST_IO_VGA);
mc->mpe_checksum = smp_compute_checksum(smp_next_mpc_entry(mc), mc->mpe_length);
mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length);
}
void write_smp_table(void *v)
{
smp_write_floating_table(v);
smp_write_config_table(v);
}

View file

@ -0,0 +1,55 @@
arch i386
mainboardinit northbridge/amd/amd76x/reset_test.inc
mainboardinit cpu/k7/earlymtrr.inc
mainboardinit northbridge/amd/amd76x/mpinit.inc
#mainboardinit southbridge/amd/amd766/disable_watchdog.inc
mainboardinit southbridge/amd/amd766/lpc_com1.inc
mainboardinit superio/winbond/w83627hf/setup_serial.inc
mainboardinit pc80/serial.inc
#mainboardinit ram/ramtest.inc
#mainboardinit mainboard/tyan/guiness/do_ramtest.inc
mainboardinit southbridge/amd/amd766/smbus.inc
#mainboardinit sdram/generic_dump_spd.inc
mainboardinit mainboard/tyan/guiness/mainboard_raminit.inc
northbridge amd/amd76x
#mainboardinit mainboard/tyan/guiness/do_ramtest.inc
#mainboardinit cpu/k7/earlymtrr.inc
southbridge amd/amd766
nsuperio winbond/w83627hf com1={1} com2={0} floppy=1 lpt=1
option RAMTEST=1
option NO_KEYBOARD
option ENABLE_FIXED_AND_VARIABLE_MTRRS
#option FINAL_MAINBOARD_FIXUP
object mainboard.o
object mptable.o
#object irq_tables.o
#keyboard pc80
dir ../../../pc80
option AMD766_DEV=0x3800
# FIXME are the SMBUS DIMM locations documented anywhere?
option SMBUS_MEM_DEVICE_START=(0xa << 3)
option SMBUS_MEM_DEVICE_END=(SMBUS_MEM_DEVICE_START +3)
option SMBUS_MEM_DEVICE_INC=1
option SIO_BASE=0x2e
option SMP=1
option IOAPIC=1
option USE_AMD_NDA_CODE=1
option FINAL_MAINBOARD_FIXUP=1
option HAVE_HARD_RESET=1
option HAVE_MP_TABLE=1
option STACK_SIZE=0x10000
option MAX_CPUS=2
option XIP_ROM_SIZE=0x8000
option XIP_ROM_BASE=0xffff8000
nooption MEMORY_HOLE
cpu p5
cpu p6
cpu k7

View file

@ -0,0 +1,28 @@
#if 0
movl $0x000f0000, %eax
movl $0x000f1000, %ebx
CALLSP(ramtest)
#endif
#if 1
movl $0x00100000, %eax
movl $0x00180000, %ebx
CALLSP(ramtest)
xorl %eax, %eax
movl $0x00080000, %ebx
CALLSP(ramtest)
#endif
#if 1
xorl %eax, %eax
movl $0x00001000, %ebx
CALLSP(ramtest)
#endif
#if 0
movl $0xffe00000, %eax
movl $0xfff00000, %ebx
CALLSP(ramtest)
#endif

View file

@ -0,0 +1,546 @@
#include <pci_ids.h>
#include <pci.h>
#include <arch/io.h>
#include <printk.h>
#include <delay.h>
#include <part/mainboard.h>
#include <part/hard_reset.h>
static void lpc_routing_fixup(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,0);
if (dev != NULL) {
#if 0
/* Send ACPI, keyboard controller,
* FDC2, FDC1, ECP
* to the LPC bus
*/
pci_write_config_byte(dev, 0x51, (1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1));
#else
/* Send keyboard controller,
* FDC1, ECP
* to the LPC bus
* Send APCI ports 0x62 & 0x66 to the ISA bus
*/
pci_write_config_byte(dev, 0x51, (0<<7)|(1<<6)|(0<<5)|(1<<4)|(0<<3)|(1));
#endif
/* Route io for both serial ports to the LPC bus */
pci_write_config_byte(dev, 0x52, (1<<7)|(1<<4)|(1<<3)|(0<<0));
/* Don't route any audio ports to the LPC bus */
pci_write_config_byte(dev, 0x53, (0<<6)|(0<<4)|(0<<3)|(0<<2)|(0<<0));
/* Route superio configuration accesses to the LPC bus */
pci_write_config_byte(dev, 0x54, (0<<5)|(1<<4)|(0<<2)|(0<<0));
/* Don't use LPC decode register 4 */
pci_write_config_byte(dev, 0x55, (0<<4)|(0<<0));
/* Don't use LPC decode register 5 */
pci_write_config_byte(dev, 0x56, (0<<4)|(0<<0));
/* Route 512 byte io address range 0x0c00 - 0xc200 the LPC bus */
pci_write_config_dword(dev, 0x58, 0x00000c01);
/* Route 1MB memory address range 0 - 0 to the LPC bus */
pci_write_config_dword(dev, 0x5c, 0x00000000);
}
}
static void enable_ioapic(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,0);
if (dev != NULL) {
/* Enable the ioapic */
pci_write_config_byte(dev, 0x4b, (0 << 3)|(0 <<2)|(0 << 1)|(1<< 0));
}
}
static void serial_irq_fixup(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 0);
if (dev != NULL) {
/* Setup serial irq's for the LPC bus. */
pci_write_config_byte(dev, 0x4a, (1<<6)|(0<<2)|(0<<0));
}
}
static void mouse_sends_irq12(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 0);
if (dev != NULL) {
unsigned short word;
/* Setup so irq12 is sent by the ps2 mouse port. */
pci_read_config_word(dev, 0x46, &word);
pci_write_config_word(dev, 0x46, word | (1<<9));
}
}
static void disable_watchdog(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 0);
if (dev != NULL) {
unsigned char byte;
/* Disable the watchdog timer */
pci_read_config_byte(dev, 0x41, &byte);
pci_write_config_byte(dev, 0x41, byte | (1<<6)|(1<<2));
}
}
static void enable_reset_port_0xcf9(void)
{
/* FIXME this code is correct but the bit isn't getting set on my test machine. */
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 0);
if (dev != NULL) {
unsigned char byte;
/* Enable reset port 0xcf9 */
pci_read_config_byte(dev, 0x41, &byte);
pci_write_config_byte(dev, 0x41, byte | (1<<5));
}
}
static void enable_port92_reset(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0);
if (dev != NULL) {
unsigned char byte;
/* Enable reset using port 0x92 */
pci_read_config_byte(dev, 0x41, &byte);
pci_write_config_byte(dev, 0x41, byte | (1<<5));
}
}
static void print_whami(void)
{
struct pci_dev *dev;
u32 whami;
/* Find out which processor I'm running on, and if it was the boot
* procesor so I can verify everything was setup correctly
*/
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C,0);
if (dev != NULL) {
pci_read_config_dword(dev, 0x80, &whami);
printk_spew("whami = 0x%08lx\n", whami);
}
}
#define IDE_ERR_ICRC 0x80 /* ATA Ultra DMA bad CRC */
#define IDE_ERR_BBK 0x80 /* ATA bad block */
#define IDE_ERR_UNC 0x40 /* ATA uncorrected error */
#define IDE_ERR_MC 0x20 /* ATA media change */
#define IDE_ERR_IDNF 0x10 /* ATA id not found */
#define IDE_ERR_MCR 0x08 /* ATA media change request */
#define IDE_ERR_ABRT 0x04 /* ATA command aborted */
#define IDE_ERR_NTK0 0x02 /* ATA track 0 not found */
#define IDE_ERR_NDAM 0x01 /* ATA address mark not found */
#define IDE_STATUS_BSY 0x80 /* busy */
#define IDE_STATUS_RDY 0x40 /* ready */
#define IDE_STATUS_DF 0x20 /* device fault */
#define IDE_STATUS_WFT 0x20 /* write fault (old name) */
#define IDE_STATUS_SKC 0x10 /* seek complete */
#define IDE_STATUS_DRQ 0x08 /* data request */
#define IDE_STATUS_CORR 0x04 /* corrected */
#define IDE_STATUS_IDX 0x02 /* index */
#define IDE_STATUS_ERR 0x01 /* error (ATA) */
#define IDE_STATUS_CHK 0x01 /* check (ATAPI) */
#define IDE_CTRL_HD15 0x08 /* bit should always be set to one */
#define IDE_CTRL_SRST 0x04 /* soft reset */
#define IDE_CTRL_NIEN 0x02 /* disable interrupts */
/* Most mandtory and optional ATA commands (from ATA-3), */
#define IDE_CMD_CFA_ERASE_SECTORS 0xC0
#define IDE_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
#define IDE_CMD_CFA_TRANSLATE_SECTOR 0x87
#define IDE_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
#define IDE_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
#define IDE_CMD_CHECK_POWER_MODE1 0xE5
#define IDE_CMD_CHECK_POWER_MODE2 0x98
#define IDE_CMD_DEVICE_RESET 0x08
#define IDE_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
#define IDE_CMD_FLUSH_CACHE 0xE7
#define IDE_CMD_FORMAT_TRACK 0x50
#define IDE_CMD_IDENTIFY_DEVICE 0xEC
#define IDE_CMD_IDENTIFY_DEVICE_PACKET 0xA1
#define IDE_CMD_IDENTIFY_PACKET_DEVICE 0xA1
#define IDE_CMD_IDLE1 0xE3
#define IDE_CMD_IDLE2 0x97
#define IDE_CMD_IDLE_IMMEDIATE1 0xE1
#define IDE_CMD_IDLE_IMMEDIATE2 0x95
#define IDE_CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
#define IDE_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
#define IDE_CMD_NOP 0x00
#define IDE_CMD_PACKET 0xA0
#define IDE_CMD_READ_BUFFER 0xE4
#define IDE_CMD_READ_DMA 0xC8
#define IDE_CMD_READ_DMA_QUEUED 0xC7
#define IDE_CMD_READ_MULTIPLE 0xC4
#define IDE_CMD_READ_SECTORS 0x20
#define IDE_CMD_READ_VERIFY_SECTORS 0x40
#define IDE_CMD_RECALIBRATE 0x10
#define IDE_CMD_SEEK 0x70
#define IDE_CMD_SET_FEATURES 0xEF
#define IDE_CMD_SET_MULTIPLE_MODE 0xC6
#define IDE_CMD_SLEEP1 0xE6
#define IDE_CMD_SLEEP2 0x99
#define IDE_CMD_STANDBY1 0xE2
#define IDE_CMD_STANDBY2 0x96
#define IDE_CMD_STANDBY_IMMEDIATE1 0xE0
#define IDE_CMD_STANDBY_IMMEDIATE2 0x94
#define IDE_CMD_WRITE_BUFFER 0xE8
#define IDE_CMD_WRITE_DMA 0xCA
#define IDE_CMD_WRITE_DMA_QUEUED 0xCC
#define IDE_CMD_WRITE_MULTIPLE 0xC5
#define IDE_CMD_WRITE_SECTORS 0x30
#define IDE_CMD_WRITE_VERIFY 0x3C
static void reset_ide_controller(unsigned ide_ctl, unsigned ide_data)
{
unsigned char status, error;
printk_spew("resetting ide controller at 0x%04x\n", ide_ctl);
outb(IDE_CTRL_HD15 | IDE_CTRL_SRST | IDE_CTRL_NIEN, ide_ctl);
printk_spew("1\n");
udelay(25);
printk_spew("2\n");
outb(IDE_CTRL_HD15 | IDE_CTRL_NIEN, ide_ctl);
printk_spew("3\n");
do {
mdelay(2);
printk_spew("4\n");
error = inb_p(ide_data+1);
status = inb_p(ide_data+7);
printk_spew("error = 0x%02x status = 0x%02x\n", error, status);
} while(status & IDE_STATUS_BSY);
printk_spew("reset ide controller at 0x%04x\n", ide_ctl);
}
static void setup_ide_devices(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, 0);
if (dev != NULL) {
/* Enable ide devices so the linux ide driver will work */
u16 word;
pci_read_config_word(dev, 0x40, &word);
/* enable:
* both devices
* both devices posted write buffers
*/
pci_write_config_word(dev, 0x40, word |(1<<14)|(1<<12)|(1<<1)|(1<<0));
#if 1
/* Setup the appropriate ide timing */
pci_write_config_dword(dev, 0x48, 0x5e5e5e5e);
pci_write_config_byte(dev, 0x4c, 0xaa);
#endif
#if 0
/* Enable native ide native mode, at the legacy addresses */
/* This would be cool if I could receive an interrupt from
* the ide controller.
*/
{
u32 class_revision;
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_revision);
pci_write_config_dword(dev, PCI_CLASS_REVISION,
class_revision | ( 1 << 8) | (1 << 10));
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
0x1f0 | PCI_BASE_ADDRESS_SPACE_IO);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1,
0x3f6 | PCI_BASE_ADDRESS_SPACE_IO);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_2,
0x170 | PCI_BASE_ADDRESS_SPACE_IO);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_3,
0x376 | PCI_BASE_ADDRESS_SPACE_IO);
}
#endif
}
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0);
if (dev != NULL) {
unsigned char byte;
/* optimize ide dma acknowledge */
pci_read_config_byte(dev, 0x4a, &byte);
pci_write_config_byte(dev, 0x4a, byte & ~(1<<7));
}
}
static void enable_ide_devices(void)
{
u32 ide0_data = 0, ide0_ctl = 0, ide1_data = 0, ide1_ctl = 0, dma_base = 0;
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, 0);
if (dev != NULL) {
ide0_data = 0x1f0;
ide0_ctl = 0x3f6;
ide1_data = 0x170;
ide1_ctl = 0x376;
pci_read_config_dword(dev, PCI_BASE_ADDRESS_4, &dma_base);
if (dma_base & PCI_BASE_ADDRESS_SPACE_IO) {
dma_base &= ~PCI_BASE_ADDRESS_SPACE_IO;
} else {
dma_base = 0;
}
}
#if 0
/* IDE resets take forever, plus my reset code looks broken... */
if (ide0_data && ide0_ctl) {
reset_ide_controller(ide0_ctl,ide0_data + 7);
}
if (ide0_data && ide1_ctl) {
reset_ide_controller(ide1_ctl, ide1_data + 7);
}
#endif
if (dma_base) {
printk_debug("ide dma_base = 0x%08lx\n", dma_base);
#if 1
/* Disable DMA */
outb_p(inb_p(dma_base + 2) & ~((1<<5)|(1<<6)), dma_base +2);
outb_p(inb_p(dma_base+8 + 2) & ~((1<<5)|(1<<6)), dma_base+8 +2);
#endif
#if 0
/* Enable DMA */
outb_p(inb_p(dma_base + 2) | ((1<<5)|(1<<6)), dma_base +2);
outb_p(inb_p(dma_base+8 + 2) | ((1<<5)|(1<<6)), dma_base+8 +2);
#endif
}
}
static void fixup_adaptec_7899P(struct pci_dev *pdev)
{
/* Enable writes to the device id */
pci_write_config_byte(pdev, 0xff, 1);
/* Set the device id */
pci_write_config_word(pdev, PCI_DEVICE_ID, PCI_DEVICE_ID_ADAPTEC2_7899P);
/* Set the subsytem vendor id */
pci_write_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, PCI_VENDOR_ID_TYAN);
/* Set the subsytem id */
pci_write_config_word(pdev, PCI_SUBSYSTEM_ID, 0x2462);
/* Disable writes to the device id */
pci_write_config_byte(pdev, 0xff, 0);
}
static void onboard_scsi_fixup(void)
{
struct pci_dev *dev;
/* Set the scsi device id's */
dev = pci_find_slot(0, PCI_DEVFN(0xd, 0));
if (dev != NULL) {
fixup_adaptec_7899P(dev);
}
/* Set the scsi device id's */
dev = pci_find_slot(0, PCI_DEVFN(0xd, 1));
if (dev != NULL) {
fixup_adaptec_7899P(dev);
}
}
static void cpu_reset_sends_init(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0);
if (dev != NULL) {
unsigned char byte;
pci_read_config_byte(dev, 0x47, &byte);
pci_write_config_byte(dev, 0x47, byte | (1<<7));
}
}
static void decode_stop_grant_fixup(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 0);
if (dev != NULL) {
unsigned char byte;
pci_read_config_byte(dev, 0x41, &byte);
pci_write_config_byte(dev, 0x41, byte | (1<<1));
}
}
static void pm_controller_classcode_fixup(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 0);
if (dev != NULL) {
pci_write_config_dword(dev, 0x60, 0x06800000);
}
}
#if 0
static void set_power_on_after_power_fail(int enable)
{
/* FIXME: This may be part of the picture but it isn't
* the whole story :(
*/
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 0);
if (dev != NULL) {
unsigned char byte;
pci_read_config_byte(dev, 0x43, &byte);
if (enable) {
byte &= ~(1<<6);
}
else {
byte |= (1<<6);
}
pci_write_config_byte(dev, 0x43, byte);
}
}
#endif
static void posted_memory_write_enable(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0);
if (dev != NULL) {
unsigned char byte;
pci_read_config_byte(dev, 0x46, &byte);
pci_write_config_byte(dev, 0x46, byte | (1<<0));
}
}
static void setup_pci_irq_to_isa_routing(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, 0);
if (dev != NULL) {
/*
* PIRQA -> 5
* PIRQB -> 10
* PIRQC -> 11
* PIRQD -> 3
*/
pci_write_config_word(dev, 0x56, 0x3ba5);
}
}
static void setup_pci_arbiter(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, 0);
if (dev) {
/* Enable:
* PCI parking
* memory prefetching
* EV6 mode
* Enable power management registers
* The southbridge lock
* Read data error disable
* PCI retries
* AGP retries
* AGP chaining
* PCI chaining
*/
pci_write_config_dword(dev, 0x84,
(0<<24)
|(1<<23)
|(1<<17)|(1<<16)
|(0<<15)|(1<<14)|(1<<13)|(1<<12)
|(0<<11)|(0<<10)|(0<<9)|(0<<8)
|(1<<7)|(0<<6)|(0<<5)|(1<<4)
|(0<<3)|(1<<2)|(1<<1)|(1<<0));
}
}
static void usb_setup(void)
{
/* FIXME this is untested incomplete implementation. */
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7414, 0);
if (dev) {
u32 cmd;
pci_read_config_dword(dev, PCI_COMMAND, &cmd);
pci_write_config_dword(dev, PCI_COMMAND,
cmd | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
}
}
static void hide_devices(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0);
if (dev) {
u8 byte;
pci_read_config_byte(dev, 0x48, &byte);
#if 0
/* Hide both the ide controller and the usb controller */
pci_write_config_byte(dev, 0x48, byte | (0<<3)|(1<<2)|(1<<1));
#endif
#if 0
/* Hide the usb controller */
pci_write_config_byte(dev, 0x48, byte | (0<<3)|(1<<2)|(0<<1));
#endif
#if 1
/* Hide no devices */
pci_write_config_byte(dev, 0x48, byte | (0<<3)|(0<<2)|(0<<1));
#endif
}
}
void mainboard_fixup(void)
{
disable_watchdog();
lpc_routing_fixup();
enable_ioapic();
serial_irq_fixup();
enable_reset_port_0xcf9();
enable_port92_reset();
#if 0
print_whami();
#endif
setup_ide_devices();
onboard_scsi_fixup();
cpu_reset_sends_init();
rtc_init();
decode_stop_grant_fixup();
posted_memory_write_enable();
pm_controller_classcode_fixup();
#if 1
mouse_sends_irq12();
#endif
setup_pci_irq_to_isa_routing();
setup_pci_arbiter();
isa_dma_init();
#if 0
usb_setup();
#endif
#if 0
hide_devices();
#endif
}
void final_mainboard_fixup(void)
{
#if 1
enable_ide_devices();
#endif
}
void hard_reset(void)
{
pci_set_method();
/* Allow the watchdog timer to reboot us, and enable 0xcf9 */
pcibios_write_config_byte(0, (AMD766_DEV >> 8) | 3, 0x41, (1<<5)|(1<<1));
/* Try rebooting though port 0xcf9 */
outb((0<<3)|(1<<2)|(1<<1), 0xcf9);
return;
}

View file

@ -0,0 +1,140 @@
jmp mainboard_raminit_out
#define DEFAULT_RAM_TRACE_SETTINGS 0
#define USE_ECC_SDRAM 1
/*
* Routine: spd_to_dimm_side0
* Arguments: %bl SMBUS_MEM_DEVICE
*
* Results: %edx DIMM register index
*
* Used: %ebx, %edx, %esp
* Trashed: %eflags
* Preserved: %eax, %ebx, %ecx, %esi, %edi, %ebp
*
* Effects: Dimms are not necessarily in the same order on the smbus
* as they are in chipset register indexes. This function
* maps the SMBUS device id to the logical index in
* the chipset, that is used to refer to a particular dimm.
*/
spd_to_dimm_side0:
movl %ebx, %edx
andl $0xff, %edx
subl $(SMBUS_MEM_DEVICE_START), %edx
/* 0 -> 0 */
cmpl $0, %edx
jne 1f
movl $0, %edx
RETSP
/* 1 -> 6 */
1: cmpl $1, %edx
jne 1f
movl $6, %edx
RETSP
/* 2 -> 4 */
1: cmpl $2, %edx
jne 1f
movl $4, %edx
RETSP
/* 3 -> 2 */
1: movl $2, %edx
RETSP
/*
* Routine: spd_to_dimm_side1
* Arguments: %bl SMBUS_MEM_DEVICE
*
* Results: %edx DIMM register index
*
* Used: %ebx, %edx, %esp
* Trashed: %eflags
* Preserved: %eax, %ebx, %ecx, %esi, %edi, %ebp
*
* Effects: Dimms are not necessarily in the same order on the smbus
* as they are in chipset register indexes. This function
* maps the SMBUS device id to the logical index in
* the chipset, that is used to refer to a particular dimm.
*/
spd_to_dimm_side1:
movl %ebx, %edx
andl $0xff, %edx
subl $(SMBUS_MEM_DEVICE_START), %edx
/* 0 -> 1 */
cmpl $0, %edx
jne 1f
movl $1, %edx
RETSP
/* 1 -> 7 */
1: cmpl $1, %edx
jne 1f
movl $7, %edx
RETSP
/* 2 -> 5 */
1: cmpl $2, %edx
jne 1f
movl $5, %edx
RETSP
/* 3 -> 3 */
1: movl $3, %edx
RETSP
/* Set the calibration delay. These values may need to change per mainboard
* so we put them here.
*/
sdram_software_calibration_delay:
#if DEFAULT_RAM_TRACE_SETTINGS
.byte 0x69, 0x00, 0x00, 0x6b
#else
.byte 0x69, 0x00, 0x00, 0x54
#endif
mainboard_constant_register_values:
#if DEFAULT_RAM_TRACE_SETTINGS
#else
.long 0x18c, 0x090e2d0e
.long 0x190, 0x3f0f2d0e
.long 0x194, 0x2d0e2d0e
.long 0x198, 0x2d0e2d0e
#endif
#if USE_ECC_SDRAM
.long 0x48, (3 << 14)|(2 << 10)|(0 << 8)|(0 << 4)|(0 << 0)
#else
.long 0x48, 0
#endif
mainboard_constant_register_values_end:
/*
* Routine: mainboard_verify_dram_timing
* Arguments: %edi the computed timing for the current dimm.
* Trashed: %eflags
* Results: cf clear
* %edi has a timing supported by this motherboard
* On Error:
* cf set
* %edi holds a timing not supported by this motherboard
*
* Effects: Verifies we can use the current dimm settings
* on the tyan guinness motherboard.
* Currently the only potential problem is putting
* in unregistered SDRAM.
*/
mainboard_verify_dram_timing:
testl $(1<<27), %edi
jnz mainboard_verify_dram_timing_ok
mainboard_verify_dram_timing_error:
stc
jmp mainboard_verify_dram_timing_out
mainboard_verify_dram_timing_ok:
clc
mainboard_verify_dram_timing_out:
RET_LABEL(mainboard_verify_dram_timing)
#undef DEFAULT_RAM_TRACE_SETTINGS
mainboard_raminit_out:

View file

@ -0,0 +1,158 @@
#include <arch/smp/mpspec.h>
#include <string.h>
#include <printk.h>
#include <cpu/p6/apic.h>
#define USE_ALL_CPUS 1
void smp_write_config_table(void *v)
{
static const char sig[4] = "PCMP";
static const char oem[8] = "TYAN ";
static const char productid[12] = "GUINESS ";
struct mp_config_table *mc;
mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);
memset(mc, 0, sizeof(*mc));
memcpy(mc->mpc_signature, sig, sizeof(sig));
mc->mpc_length = sizeof(*mc); /* initially just the header */
mc->mpc_spec = 0x04;
mc->mpc_checksum = 0; /* not yet computed */
memcpy(mc->mpc_oem, oem, sizeof(oem));
memcpy(mc->mpc_productid, productid, sizeof(productid));
mc->mpc_oemptr = 0;
mc->mpc_oemsize = 0;
mc->mpc_entry_count = 0; /* No entries yet... */
mc->mpc_lapic = LAPIC_ADDR;
mc->mpe_length = 0;
mc->mpe_checksum = 0;
mc->reserved = 0;
smp_write_processors(mc);
smp_write_bus(mc, 0, "PCI ");
smp_write_bus(mc, 1, "PCI ");
smp_write_bus(mc, 2, "ISA ");
smp_write_ioapic(mc, 2, 0x11, 0xfec00000);
/* ISA backward compatibility interrupts */
smp_write_intsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x00, 0x02, 0x00);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x01, 0x02, 0x01);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x00, 0x02, 0x02);
/* PCI 0x03 <-> 0x13 ? */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x02, 0x03, 0x02, 0x03);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x04, 0x02, 0x04);
/* PCI 0x05 <-> 0x12 ? */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x02, 0x05, 0x02, 0x05);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x06, 0x02, 0x06);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x07, 0x02, 0x07);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x08, 0x02, 0x08);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x09, 0x02, 0x09);
/* PCI 0x0a <-> 0x11 ? */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x02, 0x0a, 0x02, 0x0a);
/* PCI 0x0b <-> 0x10 ? */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x02, 0x0b, 0x02, 0x0b);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x0c, 0x02, 0x0c);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x0d, 0x02, 0x0d);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x0e, 0x02, 0x0e);
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x0f, 0x02, 0x0f);
/* Onboard SCSI 0 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x00, (0xd<<2)|0, 0x02, 0x10);
/* Onboard SCSI 1 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x00, (0xd<<2)|1, 0x02, 0x11);
/* Onboard eth0 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x00, (0x0f<<2)|0, 0x02, 0x12);
/* Onboard eth1 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x00, (0x10<<2)|0, 0x02, 0x13);
#if 0
/* Onboard IDE0 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x00, (0x7<<2)|1, 0x02, 0x10);
#endif
/* PCI slot 0 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x00, (0x08<<2)|0, 0x02, 0x10);
/* PCI slot 1 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
0x00, (0x09<<2)|0, 0x02, 0x11);
/* PCI Slot 2 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_HIGH,
0x00, (0x0a<<2)|0, 0x02, 0x12);
/* PCI Slot 3 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_HIGH,
0x00, (0x0b<<2)|0, 0x02, 0x13);
/* PCI Slot 4 */
smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_HIGH,
0x00, (0x0c<<2)|0, 0x02, 0x10);
/* Standard local interrupt assignments */
smp_write_lintsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x02, 0x00, MP_APIC_ALL, 0x00);
smp_write_lintsrc(mc, mp_NMI, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,
0x01, 0x00, MP_APIC_ALL, 0x01);
/* The following information in the extension section linux doesn't currnetly need
* and has just been copied from the bios for now.
*/
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_IO, 0x00000000, 0x00000000, 0x00010000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x10000000, 0x00000000, 0xe4100000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_PREFETCH, 0xf4100000, 0x00000000, 0x07f00000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0xfc000000, 0x00000000, 0x02e00000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0xfee01000, 0x00000000, 0x011ff000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000a0000, 0x00000000, 0x00024000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000c8000, 0x00000000, 0x00002000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000cc000, 0x00000000, 0x00002000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000d0000, 0x00000000, 0x00001000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000d2000, 0x00000000, 0x00001000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000d4000, 0x00000000, 0x00001000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000d6000, 0x00000000, 0x00001000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000d8000, 0x00000000, 0x00002000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000e0000, 0x00000000, 0x00012000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000f4000, 0x00000000, 0x00002000, 0x00000000);
smp_write_address_space(mc, 0x00, ADDRESS_TYPE_MEM, 0x000f8000, 0x00000000, 0x00004000, 0x00000000);
smp_write_bus_hierarchy(mc, 0x02, BUS_SUBTRACTIVE_DECODE, 0x00);
smp_write_compatibility_address_space(mc, 0x00, ADDRESS_RANGE_ADD, RANGE_LIST_IO_ISA);
smp_write_compatibility_address_space(mc, 0x00, ADDRESS_RANGE_ADD, RANGE_LIST_IO_VGA);
mc->mpe_checksum = smp_compute_checksum(smp_next_mpc_entry(mc), mc->mpe_length);
mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length);
printk_debug("Wrote the mp table end at: %p - %p\n",
mc, smp_next_mpe_entry(mc));
}
void write_smp_table(void *v)
{
printk_debug("Writing the mp table\n");
smp_write_floating_table(v);
smp_write_config_table(v);
}

View file

@ -0,0 +1,7 @@
mainboardinit northbridge/amd/amd76x/set_memory_size.inc
mainboardinit northbridge/amd/amd76x/raminit.inc
mainboardinit sdram/generic_sdram.inc
mainboardinit sdram/generic_zero_ecc_sdram.inc
mainboardinit arch/i386/lib/cpu_reset.inc
object northbridge.o

View file

@ -0,0 +1,256 @@
/* Very early on the K7 needs to setup it's multiprocessor state */
/* Extended BIU Control
* 0x44
* [23:20] P1 Speculative Read Data Movement Enable
* 0000 == Function Disabled
* 0001 == One Clock
* 0010 == Two Clocks
* ....
* 1111 == Fifteen Clocks
*
* [19:16] P0 Speculate Read Data Movement Enable
* 0000 == Function Disabled
* 0001 == One Clock
* 0010 == Two Clocks
* ....
* 1111 == Fifteen Clocks
*
* [13:11] P1 Write Data Delay (Status Register)
* [10: 8] P0 Write Data Delay (Status Register)
* [ 7: 7] 1 == Defer Write Data Movement
* [ 4: 4] P1 2 Bit Times Per Frame Enable
* Use 0 for alpha 1 for athlon
* [ 3: 3] P0 2 Bit Times Per Frame Enable
* Use 0 for alpha 1 for athlon
*
*/
/* BIU[01] Status/Control
* 0x60, 0x68
* [31:31] Probe_Enable
* 1 == Probes are sent to this processor
* 0 == Probes are not sent to this processor
* [27:25] Xca_Probe_Count
* Must be non-zero
* Recommended value 0x2
* [24:22] Xca_Read_Count
* Must be non-zero
* Recommended value 0x6
* [21:19] Xca_Write_Count
* Must be non-zero
* Recommended value 0x6
* [18:18] Halt_Disconnect_Enable
* 0 == No AMD Athlon system bus disconnect following HALT
* 1 == AMD Athlon system bus discconnect following HALT
* [17:17] Stop_Grant_Disconnect_Enable
* 0 == No AMD Athlon system bus disconnect following Stop/Grant
* 1 == AMD Athlon system bus disconnect following Stop/Grant
* special cycle
* [16:14] Probe_Limit
* 000 = 1 probe
* 001 = 2 probes
* ...
* 111 = 8 probes
* [13:10] Ack_Limit (Read only)
* 0000 = 1 unacknowledged command
* 0001 = 2 unacknowledged commands
* ...
* 1111 = 16 unacknowledged commands
* [09:09] Bypass_Enable
* 0 == No don't bypass certain memory pipe stages
* 1 == bypass some memory stages for optimal performace
* - Requires single CPU system
* - Requires clock multipler >= 4
* [08:07] SysDC_Out_Enable
* Initialized by pinstrapping during reset
* 00 == Reserved
* 01 == 1 clock
* 10 == 2 clocks
* 11 == 3 clocks
* [06:03] SysDC_In_Enable
* Initialized during pinstrapping
* 0000 == 1 clock
* 0001 == 2 clocks
* 1111 == 16 clocks
* [02:02] WR2_Read
* Initialized during pinstrapping
* [01:00] WR2_Write
* Initialized during pinstrapping
*/
#include <cpu/k7/mtrr.h>
#include <cpu/p6/apic.h>
#define BIU_CONTROL_MASK 0x00003dff
#define BIU_CONTROL ((1 << 31)|(0x2 << 25)|(0x6 << 22)|(0x6 << 19)|(0 << 18)\
|(1 << 17)|(7<<14)|(0<<9))
#define EBIU_MASK 0xffffe4ff
#define EBIU_VALUE ((0<<20)|(0<<16)|(1<<4)|(1<<3))
#define PCI_CONFIG_ADDR 0xFE000000
#define PCI_IO_ADDR 0xFC000000
#define PCI_IACK_ADDR 0xF8000000
#define PCI_SPEC_ADDR 0xF8000000
/* Read the northbridge whami register
*/
movl $0x80000080, %eax
movw $0xcf8, %dx
outl %eax, %dx
movw $0xcfc, %dx
inl %dx, %eax
/* Isolate the processor id */
movl %eax, %ebx
movl %eax, %esi
andl $0xf, %esi
#if defined(USE_AMD_NDA_CODE)
#endif
/* Figure out how many unacknowledged acks
* the AMD762 northbridge can support
*/
shll $3, %esi
movl $0x80000060, %eax
orl %esi, %eax
shrl $3, %esi
movw $0xcf8, %dx
outl %eax, %dx
movw $0xcfc, %dx
inl %dx, %eax
shrl $10, %eax
andl $0xf, %eax
addl $1, %eax
/* Move the count into a safe place. */
movl %eax, %ebp
/* Tell the processor how many unacknoledged probes the AMD762 can
* support
*/
#if defined(USE_AMD_NDA_CODE)
#endif /* USE_AMD_NDA_CODE */
/* Enable the local apic, and map it where we expect it. */
movl $APIC_BASE_MSR, %ecx
rdmsr
orl $APIC_BASE_MSR_ENABLE, %eax
andl $(~APIC_BASE_MSR_ADDR_MASK), %eax
orl $APIC_DEFAULT_BASE, %eax
xorl %edx, %edx
wrmsr
/* Save off the apic address */
movl %eax, %edi
andl $APIC_BASE_MSR_ADDR_MASK, %edi
/* Set the local apicid */
xorl %eax, %eax
shll $24, %esi
movl %esi, APIC_ID(%edi)
shrl $24, %esi
/* Set the enabled bit for the local apic
* and clear the spurious vector.
*/
movl APIC_SPIV(%edi), %eax
andl $0xfffffe0f, %eax
orl $APIC_SPIV_ENABLE, %eax
movl %eax, APIC_SPIV(%edi)
/* See if I'm the first processor to initialize. */
cmpb %bl, %bh
je bootstrap_cpu
/* I'm not the bootstrap processor */
/* clear the BSP bit */
movl $APIC_BASE_MSR, %ecx
rdmsr
andl $(~APIC_BASE_MSR_BOOTSTRAP_PROCESSOR), %eax
wrmsr
/* Send an APIC INIT to myself */
movl %esi, %eax
shll $24, %eax
movl %eax, APIC_ICR2(%edi)
movl $((0<<18)|(1<<15)|(1<<14)|(0<<11)|(5 << 8)|(0<<0)), %eax
movl %eax, APIC_ICR(%edi)
/* Wait for the ipi send to finish */
1: movl APIC_ICR(%edi), %eax
testl $APIC_ICR_BUSY, %eax
jnz 1b
/* Deassert the APIC INIT */
movl %esi, %eax
shll $24, %eax
movl %eax, APIC_ICR2(%edi)
movl $((0<<18)|(1<<15)|(0<<14)|(0<<11)|(5 << 8)|(0<<0)), %eax
movl %eax, APIC_ICR(%edi)
/* Wait for the ipi send to finish */
1: movl APIC_ICR(%edi), %eax
testl $APIC_ICR_BUSY, %eax
jnz 1b
wait_for_startup_ipi:
hlt
jmp wait_for_startup_ipi
bootstrap_cpu:
/* Set the bootstrap processor flag */
movl $APIC_BASE_MSR, %ecx
rdmsr
orl $APIC_BASE_MSR_BOOTSTRAP_PROCESSOR, %eax
wrmsr
init_cpu_bus_all:
/* Setup Common AMD Athlon system bus */
movl $0x80000044, %eax
mov $0xcf8, %dx
outl %eax, %dx
mov $0xcfc, %dx
inl %dx, %eax
andl $EBIU_MASK, %eax
orl $EBIU_VALUE, %eax
outl %eax, %dx
init_cpu_bus_0:
testl $(1<<16), %ebx
jz init_cpu_bus_0_done
/* Setup the AMD Athlon system bus */
movl $0x80000060, %eax
movw $0xcf8, %dx
outl %eax, %dx
movw $0xcfc, %dx
inl %dx, %eax
andl $BIU_CONTROL_MASK, %eax
orl $BIU_CONTROL, %eax
outl %eax, %dx
init_cpu_bus_0_done:
init_cpu_bus_1:
testl $(2<<16), %ebx
jz init_cpu_bus_1_done
/* Setup the AMD Athlon system bus */
movl $0x80000068, %eax
movw $0xcf8, %dx
outl %eax, %dx
movw $0xcfc, %dx
inl %dx, %eax
andl $BIU_CONTROL_MASK, %eax
orl $BIU_CONTROL, %eax
outl %eax, %dx
init_cpu_bus_1_done:
/* FIXME enable superbypass memory accesses if only cpu0 is present,
* and we have a cpu multiplier > 4.
*/

View file

@ -0,0 +1,14 @@
#include <pci.h>
#include <cpu/p5/io.h>
#include <part/sizeram.h>
unsigned long sizeram(void)
{
unsigned long size;
/* Use the PCI top memory register */
pcibios_read_config_dword(0, 0, 0x9c, &size);
/* Convert size in bytes to size in K */
size = size >> 10;
return size;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
/* If I have already booted once skip a bunch of initialization */
/* To see if I have already booted I check to see if memory
* has been enabled.
*/
movl $0x58, %eax
PCI_READ_CONFIG_DWORD
testl $(1<<25), %eax
jnz __cpu_reset

View file

@ -0,0 +1,14 @@
jmp set_memory_size_out
#include <cpu/k7/mtrr.h>
set_memory_size:
/* Read the top of memory */
movl $0x9c, %eax
PCI_READ_CONFIG_DWORD
#if USE_AMD_NDA_CODE
#endif /* USE_AMD_NDA_CODE */
set_memory_size_end:
RETSP
set_memory_size_out:

44
src/pc80/i8259.c Normal file
View file

@ -0,0 +1,44 @@
#ifdef I8259
#include <pc80/i8259.h>
#include <arch/io.h>
/* code taken from:
!
! setup.S Copyright (C) 1991, 1992 Linus Torvalds
!
! setup.s is responsible for getting the system data from the BIOS,
! and putting them into the appropriate places in system memory.
! both setup.s and system has been loaded by the bootblock.
*/
/* we're getting screwed again and again by this problem of the 8259.
* so we're going to leave this lying around for inclusion into
* crt0.S on an as-needed basis.
! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
! we put them right after the intel-reserved hardware interrupts, at
! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
! messed this up with the original PC, and they haven't been able to
! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
! which is used for the internal hardware interrupts as well. We just
! have to reprogram the 8259's, and it isn't fun.
*/
void setup_i8259(void)
{
outb(0x11, 0x20); /*! initialization sequence to 8259A-1*/
outb(0x11, 0xA0); /*! and to 8259A-2*/
outb(0x20, 0x21); /*! start of hardware int's (0x20)*/
outb(0x28, 0xA1); /*! start of hardware int's 2 (0x28)*/
outb(0x04, 0x21); /*! 8259-1 is master*/
outb(0x02, 0xA1); /*! 8259-2 is slave*/
outb(0x01, 0x21); /*! 8086 mode for both*/
outb(0x01, 0xA1);
outb(0xFF, 0xA1); /*! mask off all interrupts for now*/
outb(0xFB, 0x21); /*! mask all irq's but irq2 which is cascaded*/
}
/*
* I like the way Linus says it:
! Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
! need no steenking BIOS anyway (except for the initial loading :-).
*/
#endif /* I8259 */

43
src/pc80/isa-dma.c Normal file
View file

@ -0,0 +1,43 @@
#include <arch/io.h>
/* DMA controller registers */
#define DMA1_CMD_REG 0x08 /* command register (w) */
#define DMA1_STAT_REG 0x08 /* status register (r) */
#define DMA1_REQ_REG 0x09 /* request register (w) */
#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
#define DMA1_MODE_REG 0x0B /* mode register (w) */
#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
#define DMA2_CMD_REG 0xD0 /* command register (w) */
#define DMA2_STAT_REG 0xD0 /* status register (r) */
#define DMA2_REQ_REG 0xD2 /* request register (w) */
#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
#define DMA2_MODE_REG 0xD6 /* mode register (w) */
#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */
#define DMA_AUTOINIT 0x10
void isa_dma_init(void)
{
/* slave at 0x00 - 0x0f */
/* master at 0xc0 - 0xdf */
/* 0x80 - 0x8f DMA page registers */
/* DMA: 0x00, 0x02, 0x4, 0x06 base address for DMA channel */
outb(0, DMA1_RESET_REG);
outb(0, DMA2_RESET_REG);
outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
outb(0, DMA2_MASK_REG);
}

View file

@ -2,7 +2,7 @@
static char rcsid[] = "$Id$";
#endif
#include <cpu/p5/io.h>
#include <arch/io.h>
#include <subr.h>
/* much better keyboard init courtesy ollie@sis.com.tw
TODO: Typematic Setting, the keyboard is too slow for me */
@ -13,7 +13,7 @@ void pc_keyboard_init()
/* send cmd = 0xAA, self test 8042 */
outb(0xaa, 0x64);
/* empty inut bufferm or any other command/data will be lost */
/* empty input buffer or any other command/data will be lost */
while ((inb(0x64) & 0x02))
post_code(0);
/* empty output buffer or any other command/data will be lost */
@ -52,3 +52,4 @@ void pc_keyboard_init()
if ((regval = inb(0x60) != 0xaa))
return;
}

161
src/pc80/mc146818rtc.c Normal file
View file

@ -0,0 +1,161 @@
#include <arch/io.h>
#include <printk.h>
#define RTC_PORT(x) (0x70 + (x))
#define CMOS_READ(addr) ({ \
outb_p((addr),RTC_PORT(0)); \
inb_p(RTC_PORT(1)); \
})
#define CMOS_WRITE(val, addr) ({ \
outb_p((addr),RTC_PORT(0)); \
outb_p((val),RTC_PORT(1)); \
})
/* control registers - Moto names
*/
#define RTC_REG_A 10
#define RTC_REG_B 11
#define RTC_REG_C 12
#define RTC_REG_D 13
/**********************************************************************
* register details
**********************************************************************/
#define RTC_FREQ_SELECT RTC_REG_A
/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
* reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
* totalling to a max high interval of 2.228 ms.
*/
# define RTC_UIP 0x80
# define RTC_DIV_CTL 0x70
/* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
# define RTC_REF_CLCK_4MHZ 0x00
# define RTC_REF_CLCK_1MHZ 0x10
# define RTC_REF_CLCK_32KHZ 0x20
/* 2 values for divider stage reset, others for "testing purposes only" */
# define RTC_DIV_RESET1 0x60
# define RTC_DIV_RESET2 0x70
/* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
# define RTC_RATE_SELECT 0x0F
# define RTC_RATE_NONE 0x00
# define RTC_RATE_32786HZ 0x01
# define RTC_RATE_16384HZ 0x02
# define RTC_RATE_8192HZ 0x03
# define RTC_RATE_4096HZ 0x04
# define RTC_RATE_2048HZ 0x05
# define RTC_RATE_1024HZ 0x06
# define RTC_RATE_512HZ 0x07
# define RTC_RATE_256HZ 0x08
# define RTC_RATE_128HZ 0x09
# define RTC_RATE_64HZ 0x0a
# define RTC_RATE_32HZ 0x0b
# define RTC_RATE_16HZ 0x0c
# define RTC_RATE_8HZ 0x0d
# define RTC_RATE_4HZ 0x0e
# define RTC_RATE_2HZ 0x0f
/**********************************************************************/
#define RTC_CONTROL RTC_REG_B
# define RTC_SET 0x80 /* disable updates for clock setting */
# define RTC_PIE 0x40 /* periodic interrupt enable */
# define RTC_AIE 0x20 /* alarm interrupt enable */
# define RTC_UIE 0x10 /* update-finished interrupt enable */
# define RTC_SQWE 0x08 /* enable square-wave output */
# define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
# define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
# define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
/**********************************************************************/
#define RTC_INTR_FLAGS RTC_REG_C
/* caution - cleared by read */
# define RTC_IRQF 0x80 /* any of the following 3 is active */
# define RTC_PF 0x40
# define RTC_AF 0x20
# define RTC_UF 0x10
/**********************************************************************/
#define RTC_VALID RTC_REG_D
# define RTC_VRT 0x80 /* valid RAM and time */
/**********************************************************************/
/* On PCs, the checksum is built only over bytes 16..45 */
#define PC_CKS_RANGE_START 16
#define PC_CKS_RANGE_END 45
#define PC_CKS_LOC 46
static int rtc_checksum_valid(void)
{
int i;
unsigned sum, old_sum;
sum = 0;
for(i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; i++) {
sum += CMOS_READ(i);
}
sum &= 0xffff;
old_sum = (CMOS_READ(PC_CKS_LOC) << 8) | CMOS_READ(PC_CKS_LOC+1);
return sum == old_sum;
}
static void rtc_set_checksum(void)
{
int i;
unsigned sum;
sum = 0;
for(i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; i++) {
sum += CMOS_READ(i);
}
sum &= 0xffff;
CMOS_WRITE(((sum >> 8) & 0xff), PC_CKS_LOC);
CMOS_WRITE(((sum >> 0) & 0xff), PC_CKS_LOC+1);
}
#define RTC_CONTROL_DEFAULT (RTC_24H)
#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ)
#if 0 /* alpha setup */
#undef RTC_CONTROL_DEFAULT
#undef RTC_FREQ_SELECT_DEFAULT
#define RTC_CONTROL_DEFAULT (RTC_SQWE | RTC_24H)
#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ)
#endif
void rtc_init(void)
{
unsigned char x;
int cmos_valid;
/* See if there has been a CMOS power problem. */
x = CMOS_READ(RTC_VALID);
cmos_valid = !(x & RTC_VRT);
/* See if there is a CMOS checksum error */
cmos_valid = rtc_checksum_valid();
if (!cmos_valid) {
int i;
printk_warning("RTC power problem, zeroing cmos\n");
for(i = 0x0; i < 128; i++) {
CMOS_WRITE(0, i);
}
/* Now setup a default date of Sat 1 January 2000 */
CMOS_WRITE(0, 0x00); /* seconds */
CMOS_WRITE(0, 0x02); /* minutes */
CMOS_WRITE(1, 0x04); /* hours */
CMOS_WRITE(7, 0x06); /* day of week */
CMOS_WRITE(1, 0x07); /* day of month */
CMOS_WRITE(1, 0x08); /* month */
CMOS_WRITE(0, 0x09); /* year */
}
/* Setup the real time clock */
CMOS_WRITE(RTC_CONTROL_DEFAULT, RTC_CONTROL);
/* Setup the frequency it operates at */
CMOS_WRITE(RTC_FREQ_SELECT_DEFAULT, RTC_FREQ_SELECT);
/* Make certain we have a valid checksum */
rtc_set_checksum();
/* Clear any pending interrupts */
(void) CMOS_READ(RTC_INTR_FLAGS);
}

View file

@ -0,0 +1,38 @@
dump_spd_registers:
movl $((0 << 8) | SMBUS_MEM_DEVICE_START), %ebx
dump_spd_reg_dimm:
TTYS0_TX_CHAR($'\r')
TTYS0_TX_CHAR($'\n')
TTYS0_TX_CHAR($'d')
TTYS0_TX_CHAR($'i')
TTYS0_TX_CHAR($'m')
TTYS0_TX_CHAR($'m')
TTYS0_TX_CHAR($' ')
movb %bl, %al
CALLSP(ttys0_tx_hex8)
TTYS0_TX_CHAR($'\r')
TTYS0_TX_CHAR($'\n')
dump_spd_reg_byte:
CALLSP(smbus_read_byte)
jz dump_spd_reg_next_dimm
CALLSP(ttys0_tx_hex8)
TTYS0_TX_CHAR($' ')
incb %bh
testb $0x0F, %bh
jnz dump_spd_reg_next_byte
TTYS0_TX_CHAR($'\r')
TTYS0_TX_CHAR($'\n')
dump_spd_reg_next_byte:
cmpb $0, %bh
jne dump_spd_reg_byte
dump_spd_reg_next_dimm:
TTYS0_TX_CHAR($'\r')
TTYS0_TX_CHAR($'\n')
xorb %bh, %bh
add $SMBUS_MEM_DEVICE_INC, %bl
cmpb $(SMBUS_MEM_DEVICE_END + SMBUS_MEM_DEVICE_INC), %bl
jne dump_spd_reg_dimm
dump_spd_registers_out:

View file

@ -0,0 +1,73 @@
jmp generic_sdram_enable_out
ram_enable_1: .string "Ram Enable 1\r\n"
ram_enable_2: .string "Ram Enable 2\r\n"
ram_enable_3: .string "Ram Enable 3\r\n"
ram_enable_4: .string "Ram Enable 4\r\n"
ram_enable_5: .string "Ram Enable 5\r\n"
/* Estimate that SLOW_DOWN_IO takes about 50&76us*/
/* delay for 200us */
#define DO_DELAY \
movl $4, %edi ; \
1: SLOW_DOWN_IO ; \
decl %edi ; \
jnz 1b
enable_sdram:
/* now the fun begins.
turn on the dram and wait a while (this from the intel book)
turn power on and set the nop bit too
*/
TTYS0_TX_STRING($ram_enable_1)
/* SDRAMC */
SET_RAM_COMMAND(RAM_COMMAND_NOP)
DO_DELAY
ASSERT_RAM_COMMAND() /* nop command */
/* Precharge all */
SET_RAM_COMMAND(RAM_COMMAND_PRECHARGE)
ASSERT_RAM_COMMAND()
/* wait until the all banks idle state... */
TTYS0_TX_STRING($ram_enable_2)
/* Now we need 8 AUTO REFRESH / CBR cycles to be performed */
SET_RAM_COMMAND(RAM_COMMAND_CBR)
ASSERT_RAM_COMMAND()
ASSERT_RAM_COMMAND()
ASSERT_RAM_COMMAND()
ASSERT_RAM_COMMAND()
ASSERT_RAM_COMMAND()
ASSERT_RAM_COMMAND()
ASSERT_RAM_COMMAND()
ASSERT_RAM_COMMAND()
TTYS0_TX_STRING($ram_enable_3)
/* mode register set */
SET_RAM_MODE_REGISTER
/* MAx[14:0] lines,
* MAx[2:0 ] 010 == burst mode of 4
* MAx[3:3 ] 1 == interleave wrap type
* MAx[4:4 ] == CAS# latency bit
* MAx[6:5 ] == 01
* MAx[12:7] == 0
*/
TTYS0_TX_STRING($ram_enable_4)
/* normal operation */
SET_RAM_COMMAND(RAM_COMMAND_NONE)
TTYS0_TX_STRING($ram_enable_5)
RET_LABEL(enable_sdram)
generic_sdram_enable_out:

View file

@ -0,0 +1,102 @@
jmp ecc_ram_initialize
ecc_ram_1: .string "ecc_ram_1\r\n"
ecc_ram_2: .string "ecc_ram_2\r\n"
ecc_ram_3: .string "ecc_ram_3\r\n"
ecc_ram_4: .string "ecc_ram_4\r\n"
ecc_ram_initialize:
TTYS0_TX_STRING($ecc_ram_1)
CALL_LABEL(get_ecc_ram_size_bytes_ebx)
/* If we don't have an ECC SDRAM size skip the zeroing */
testl %ebx, %ebx
jz zero_ecc_ram_out
movl %ebx, %ebp
/* Compute the next greater power of two memory size, to use in the mtrrs */
bsrl %ebp, %ecx
movl $1, %esi
shll %cl, %esi
/* See if I need to round up */
subl $1, %esi
testl %esi, %ebp
jz 1f
incl %ecx
1: movl $1, %esi
shll %cl, %esi
/* Set caching on all of memory into write-combining mode.
* So we can zero it quickly.
*/
/* Disable the cache while we set up a new MTRR over memory */
movl %cr0, %eax
orl $0x40000000, %eax
movl %eax, %cr0
movl $0x200, %ecx /* mtrr[0] physical base register */
movl $0x00000000, %edx
movl $0x00000001, %eax
wrmsr
movl $0x201, %ecx /* mtrr[0] physical mask register */
movl $0x0000000f, %edx
xorl %eax, %eax
subl %esi, %eax
andl $0xfffff000, %eax
orl $0x800, %eax
wrmsr
/* Reenable the cache now that the mtrr is set up */
movl %cr0, %eax
andl $0x9fffffff, %eax
movl %eax, %cr0
/* Now zero the memory */
TTYS0_TX_STRING($ecc_ram_2)
cld
#if !defined(HAVE_PC80_MEMORY_HOLE)
/* The 640KB - 1MB memory should not be enabled at this point. */
xorl %eax, %eax
xorl %edi, %edi
movl %ebp, %ecx
shrl $2, %ecx
rep stosl
#else /* HAVE_PC80_MEMORY_HOLE */
xorl %eax, %eax /* zero */
xorl %edi, %edi /* destination */
movl $0x28000,%ecx
rep stosl
xorl %eax, %eax
movl $0x100000, %edi
movl %ebp, %ecx
subl %edi, %ecx
shrl $2, %ecx
rep stosl
#endif /* HAVE_PC80_MEMORY_HOLE */
TTYS0_TX_STRING($ecc_ram_3)
/* Change caching on memory from write-combining to write-back. */
/* Disable the cache while we set up a new MTRR over memory */
movl %cr0, %eax
orl $0x40000000, %eax
movl %eax, %cr0
movl $0x200, %ecx
movl $0x00000000, %edx
movl $0x00000006, %eax
wrmsr
/* Reenable the cache now that the mtrr is set up */
movl %cr0, %eax
andl $0x9fffffff, %eax
movl %eax, %cr0
zero_ecc_ram_out:
TTYS0_TX_STRING($ecc_ram_4)

View file

@ -1,5 +1,5 @@
/* Useful macros PCIBUS, and SMBUS functions for getting DRAM going. */
/* courtesy Eric Beiderman of linuxnetworx.com */
/* courtesy Eric Biederman of linuxnetworx.com */
#define CS_WRITE_BYTE(addr, byte) \
movl $addr, %eax ; \

View file

@ -0,0 +1,3 @@
object southbridge.o
object nvram.o

View file

@ -0,0 +1,10 @@
#define PM_DEV_FN (AMD766_DEV + 0x300)
/* Disable the watchdog timer */
movl $(0x80000000 | PM_DEV_FN | 0x40), %eax
movw $0xcf8, %dx
outl %eax, %dx
movw $0xcfd, %dx
inb %dx, %al
orb $0x44, %al
outb %al, %dx

View file

@ -0,0 +1,16 @@
/* enable LPC superio on the AMD 766 south bridge */
movl $(0x80000000 | AMD766_DEV | 0x54), %eax
movw $0xcf8, %dx
outl %eax, %dx
movw $0xcfc, %dx
inb %dx, %al
orb $0x30, %al
outb %al, %dx
/* enable LPC serial port 0x3f8 */
movl $(0x80000000 | AMD766_DEV | 0x50), %eax
movw $0xcf8, %dx
outl %eax, %dx
movw $0xcfe, %dx
movb $0x8, %al
outb %al, %dx

View file

@ -0,0 +1,18 @@
#include <pci_ids.h>
#include <pci.h>
#include <cpu/p5/io.h>
#include <part/nvram.h>
void nvram_on(void)
{
struct pci_dev *dev;
dev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0);
if (dev != NULL) {
u8 segen;
u32 regval;
pci_read_config_byte(dev, 0x43, &segen);
/* Enable 4MB rom access at 0xFFC00000 - 0xFFFFFFFF */
segen |= 0x80;
pci_write_config_byte(dev, 0x43, segen);
}
}

View file

@ -0,0 +1,182 @@
jmp smbus_code_end
#define PM_DEV_FN (AMD766_DEV + 0x300)
#define PM_BASE 0xDD00
#define SMBUS_IO_BASE (PM_BASE + 0xE0)
#define SMB_GSTAT (SMBUS_IO_BASE + 0x0)
#define SMB_GCTL (SMBUS_IO_BASE + 0x2)
#define SMB_HOST_ADDR (SMBUS_IO_BASE + 0x4)
#define SMB_HOST_DAT (SMBUS_IO_BASE + 0x6)
#define SMB_HOST_CMD (SMBUS_IO_BASE + 0x8)
#define SMB_BLKDAT (SMBUS_IO_BASE + 0x9)
#define SMB_SLAVE_DAT (SMBUS_IO_BASE + 0xa)
#define SMB_SLAVE_DEV (SMBUS_IO_BASE + 0xc)
#define SMB_SLAVE_ADDR (SMBUS_IO_BASE + 0xe)
#define SMB_SNOOP_ADDR (SMBUS_IO_BASE + 0xf)
#define SMB_GSTAT_ABORT (1 << 0)
#define SMB_GSTAT_COLLISION (1 << 1)
#define SMB_GSTAT_PROTO_ERROR (1 << 2)
#define SMB_GSTAT_HOST_BUSY (1 << 3)
#define SMB_GSTAT_COMPLETE (1 << 4)
#define SMB_GSTAT_TIMEOUT (1 << 5)
#define SMB_GSTAT_SNOOP_MATCH (1 << 8)
#define SMB_GSTAT_SLAVE_MATCH (1 << 9)
#define SMB_GSTAT_ALERT (1 << 10)
#define SMB_GSTAT_BUSY (1 << 11)
/* The low bit of the address specifies read or write */
#define SMB_GCTL_QUICK_COMMAND 0
#define SMB_GCTL_SEND_RECV_BYTE 1
#define SMB_GCTL_WRITE_READ_BYTE 2
#define SMB_GCTL_WRITE_READ_WORD 3
#define SMB_GCTL_PROCESS_CALL 4
#define SMB_GCTL_WRITE_READ_BLOCK 5
#define SMB_GCTL_HOST_START (1 << 3)
#define SMB_GCTL_HOST_INTERRUPT (1 << 4)
#define SMB_GCTL_ABORT (1 << 5)
#define SMB_GCTL_SNOOP (1 << 8)
#define SMB_GCTL_SLAVE_INTERRUPT (1 << 9)
#define SMB_GCTL_ALERT_INTERRUPT (1 << 10)
enable_smbus:
/* Enable PM IO C3A41 */
movl $(0x80000000 | PM_DEV_FN | 0x40), %eax
movw $0xcf8, %dx
outl %eax, %dx
movw $0xcfd, %dx
inb %dx, %al
orb $0x80, %al
outb %al, %dx
/* Set the PM registers to 0xDD00 */
movl $(0x80000000 | PM_DEV_FN | 0x58), %eax
mov $0xcf8, %dx
outl %eax, %dx
movw $0xcfc, %dx
movl $(PM_BASE | 0x01), %eax
outl %eax, %dx
RET_LABEL(enable_smbus)
/*
* Routine: setup_smbus
* Arguments: none
* Results: none
* Trashed: eax, edx
* Effects: The smbus is enabled
*/
setup_smbus:
movl $(SMB_GSTAT_ABORT | SMB_GSTAT_COLLISION | \
SMB_GSTAT_PROTO_ERROR | SMB_GSTAT_COMPLETE | \
SMB_GSTAT_TIMEOUT | SMB_GSTAT_SNOOP_MATCH | \
SMB_GSTAT_SLAVE_MATCH | SMB_GSTAT_ALERT),%eax
movw $SMB_GSTAT, %dx
outb %al, %dx
RET_LABEL(setup_smbus)
/*
* Routine: smbus_wait_until_ready
* Arguments: none
* Results: none
* Trashed: eax, edx
* Effects: Upon return the smbus is ready to accept commands
*/
smbus_wait_until_ready:
movl $SMB_GSTAT, %edx
1: inb %dx, %al
testb $SMB_GSTAT_HOST_BUSY, %al
jnz 1b
RET_LABEL(smbus_wait_until_ready)
/*
* Routine: smbus_wait_until_done
* Arguments: none
* Results: none
* Trashed: eax, edx
* Effects: Upon return the smbus has completed it's most recent transation
*/
smbus_wait_until_done:
movl $SMB_GSTAT, %edx
1: inb %dx, %al
testb $(SMB_GSTAT_HOST_BUSY), %al
jnz 1b
2: testb $(~(SMB_GSTAT_HOST_BUSY)), %al
jnz 3f
inb %dx, %al
testb $(~(SMB_GSTAT_HOST_BUSY)), %al
jz 2b
3: RET_LABEL(smbus_wait_until_done)
/*
* Routine: smbus_read_byte
* Arguments: %esp return address
* %bl device on the smbus to read from
* %bh address on the smbus to read
*
* Results: zf clear
* byte read %eax
* On Error:
* zf set
* %eax trashed
*
* Trashed: %edx, %eax
* Effects: reads a byte off of the smbus
*/
smbus_read_byte:
/* poll until the smbus is ready for commands */
CALL_LABEL(smbus_wait_until_ready)
/* clear any lingering errors, so that the transaction will run */
movw $SMB_GSTAT, %dx
inw %dx, %ax
outw %ax, %dx
/* set the device I'm talking to, and set the low bit for a read */
movw $SMB_HOST_ADDR, %dx
xorl %eax, %eax
movb %bl /* device */, %al
shlb $1, %al
orb $1, %al
outw %ax, %dx
/* set the command address... */
movw $SMB_HOST_CMD, %dx
movb %bh /* address */, %al
outb %al, %dx
/* clear the data byte */
movw $SMB_HOST_DAT, %dx
xorl %eax, %eax
outw %ax, %dx
/* start a byte read, with interrupts disabled */
movw $SMB_GCTL, %dx
movl $(SMB_GCTL_HOST_START | SMB_GCTL_WRITE_READ_BYTE), %eax
outw %ax, %dx
/* poll for transaction completion */
CALL_LABEL(smbus_wait_until_done)
/* read the results and see if we succeded */
movl $SMB_GSTAT, %edx
inb %dx, %al
testb $(SMB_GSTAT_COMPLETE), %al
jz 1f
movw $SMB_HOST_DAT, %dx
inb %dx, %al
1:
RETSP
smbus_code_end:
CALL_LABEL(enable_smbus)
CALL_LABEL(setup_smbus)

View file

@ -0,0 +1,7 @@
void southbridge_fixup(void)
{
}

View file

@ -0,0 +1,51 @@
/*
* Enable the peripheral devices on the windbond w83627hf
*/
/* The base address is 0x2e,0x4e depending on config bytes */
#define SIO_INDEX SIO_BASE
#define SIO_DATA SIO_BASE+1
#define SIO_COM1_DEVICE 2
#define SIO_ENTER_PNP_MODE() \
movw $SIO_BASE, %dx ; \
movb $0x87, %al ; \
outb %al, %dx ; \
outb %al, %dx
#define SIO_EXIT_PNP_MODE() \
movw $SIO_BASE, %dx ; \
movb $0xaa, %al ; \
outb %al, %dx
#define SIO_WRITE_CONFIG(value, reg) \
movw $SIO_BASE, %dx ; \
movb $reg, %al ; \
outb %al, %dx ; \
incw %dx ; \
movb $value, %al ; \
outb %al, %dx
#define SIO_READ_CONFIG(value, reg) \
movw $SIO_BASE, %dx ; \
movb $reg, %al ; \
outb %al, %dx ; \
incw %dx ; \
inb %al, %dx
#define SIO_SET_LOGICAL_DEVICE(device) \
SIO_WRITE_CONFIG(device, 0x07)
/* enable serial 1 */
SIO_ENTER_PNP_MODE()
SIO_SET_LOGICAL_DEVICE(SIO_COM1_DEVICE)
SIO_WRITE_CONFIG(1, 0x30)
SIO_WRITE_CONFIG(0x3, 0x60)
SIO_WRITE_CONFIG(0xf8, 0x61)
SIO_EXIT_PNP_MODE()

View file

@ -0,0 +1,259 @@
#include <pci.h>
#include <cpu/p5/io.h>
#include <serial_subr.h>
#include <printk.h>
#define FLOPPY_DEVICE 0
#define PARALLEL_DEVICE 1
#define COM1_DEVICE 2
#define COM2_DEVICE 3
#define KBC_DEVICE 5
#define CIR_DEVICE 6
#define GAME_PORT_DEVICE 7
#define GPIO_PORT2_DEVICE 8
#define GPIO_PORT3_DEVICE 9
#define ACPI_DEVICE 0xa
#define HW_MONITOR_DEVICE 0xb
#define FLOPPY_DEFAULT_IOBASE 0x3f0
#define FLOPPY_DEFAULT_IRQ 6
#define FLOPPY_DEFAULT_DRQ 2
#define PARALLEL_DEFAULT_IOBASE 0x378
#define PARALLEL_DEFAULT_IRQ 7
#define PARALLEL_DEFAULT_DRQ 4 /* No dma */
#define COM1_DEFAULT_IOBASE 0x3f8
#define COM1_DEFAULT_IRQ 4
#define COM1_DEFAULT_BAUD 115200
#define COM2_DEFAULT_IOBASE 0x2f8
#define COM2_DEFAULT_IRQ 3
#define COM2_DEFAULT_BAUD 115200
#define KBC_DEFAULT_IOBASE0 0x60
#define KBC_DEFAULT_IOBASE1 0x64
#define KBC_DEFAULT_IRQ0 0x1
#define KBC_DEFAULT_IRQ1 0xc
static void enter_pnp(struct superio *sio)
{
outb(0x87, sio->port);
outb(0x87, sio->port);
}
static void exit_pnp(struct superio *sio)
{
outb(0xaa, sio->port);
}
static void write_config(struct superio *sio,
unsigned char value, unsigned char reg)
{
outb(reg, sio->port);
outb(value, sio->port +1);
}
static unsigned char read_config(struct superio *sio, unsigned char reg)
{
outb(reg, sio->port);
return inb(sio->port +1);
}
static void set_logical_device(struct superio *sio, int device)
{
write_config(sio, device, 0x07);
}
static void set_enable(struct superio *sio, int enable)
{
write_config(sio, enable?0x1:0x0, 0x30);
#if 0
if (enable) {
printk_debug("enabled superio device: %d\n",
read_config(sio, 0x07));
}
#endif
}
static void set_iobase0(struct superio *sio, unsigned iobase)
{
write_config(sio, (iobase >> 8) & 0xff, 0x60);
write_config(sio, iobase & 0xff, 0x61);
}
static void set_iobase1(struct superio *sio, unsigned iobase)
{
write_config(sio, (iobase >> 8) & 0xff, 0x62);
write_config(sio, iobase & 0xff, 0x63);
}
static void set_irq0(struct superio *sio, unsigned irq)
{
write_config(sio, irq, 0x70);
}
static void set_irq1(struct superio *sio, unsigned irq)
{
write_config(sio, irq, 0x72);
}
static void set_drq(struct superio *sio, unsigned drq)
{
write_config(sio, drq & 0xff, 0x74);
}
static void enable_com(struct superio *sio,
struct com_ports *com, int device)
{
int divisor = 115200/com->baud;
printk_debug("Enabling com device: %02x\n", device);
printk_debug(" iobase = 0x%04x irq=%d\n", com->base, com->irq);
/* Select the device */
set_logical_device(sio, device);
/* Disable it while it is initialized */
set_enable(sio, 0);
if (com->enable) {
set_iobase0(sio, com->base);
set_irq0(sio, com->irq);
/* We are initialized so enable the device */
set_enable(sio, 1);
/* Now initialize the com port */
uart_init(com->base, divisor);
}
}
static void enable_floppy(struct superio *sio)
{
/* Remember the default resources */
unsigned iobase = FLOPPY_DEFAULT_IOBASE;
unsigned irq = FLOPPY_DEFAULT_IRQ;
unsigned drq = FLOPPY_DEFAULT_DRQ;
/* Select the device */
set_logical_device(sio, FLOPPY_DEVICE);
/* Disable it while initializing */
set_enable(sio, 0);
if (sio->lpt) {
set_iobase0(sio, iobase);
set_irq0(sio, irq);
set_drq(sio, drq);
set_enable(sio, 1);
}
}
static void enable_parallel(struct superio *sio)
{
/* Remember the default resources */
unsigned iobase = PARALLEL_DEFAULT_IOBASE;
unsigned irq = PARALLEL_DEFAULT_IRQ;
unsigned drq = PARALLEL_DEFAULT_DRQ;
/* Select the device */
set_logical_device(sio, PARALLEL_DEVICE);
/* Disable it while initializing */
set_enable(sio, 0);
if (sio->lpt) {
set_iobase0(sio, iobase);
set_irq0(sio, irq);
set_drq(sio, drq);
set_enable(sio, 1);
}
}
static void enable_keyboard(struct superio *sio)
{
/* Remember the default resources */
unsigned iobase0 = KBC_DEFAULT_IOBASE0;
unsigned iobase1 = KBC_DEFAULT_IOBASE1;
unsigned irq0 = KBC_DEFAULT_IRQ0;
unsigned irq1 = KBC_DEFAULT_IRQ1;
/* Select the device */
set_logical_device(sio, KBC_DEVICE);
/* Disable it while initializing */
set_enable(sio, 0);
if (sio->lpt) {
set_iobase0(sio, iobase0);
set_iobase1(sio, iobase1);
set_irq0(sio, irq0);
set_irq1(sio, irq1);
set_enable(sio, 1);
/* Initialize the keyboard */
pc_keyboard_init();
}
}
#if 0
static void setup_acpi_registers(struct superio *sio)
{
set_logical_device(sio, ACPI_DEVICE);
/* Enable power on after power fail */
write_config(sio, (1 << 7)|(0 <<5), 0xe4);
set_enable(sio, 1);
}
#endif
static void enable_devices(struct superio *sio)
{
if (sio->port == 0) {
sio->port = sio->super->defaultport;
}
if (sio->com1.base == 0) sio->com1.base = COM1_DEFAULT_IOBASE;
if (sio->com1.irq == 0) sio->com1.irq = COM1_DEFAULT_IRQ;
if (sio->com1.baud == 0) sio->com1.baud = COM1_DEFAULT_BAUD;
if (sio->com2.base == 0) sio->com2.base = COM2_DEFAULT_IOBASE;
if (sio->com2.irq == 0) sio->com2.irq = COM2_DEFAULT_IRQ;
if (sio->com2.baud == 0) sio->com2.baud = COM2_DEFAULT_BAUD;
enter_pnp(sio);
/* enable floppy */
enable_floppy(sio);
/* enable parallel */
enable_parallel(sio);
/* enable com1 */
enable_com(sio, &sio->com1, COM1_DEVICE);
/* enable com2 */
enable_com(sio, &sio->com2, COM2_DEVICE);
/* enable keyboard */
enable_keyboard(sio);
/* disable cir */
set_logical_device(sio, CIR_DEVICE);
set_enable(sio, 0);
/* disable game */
set_logical_device(sio, GAME_PORT_DEVICE);
set_enable(sio, 0);
/* disable gpio_port2 */
set_logical_device(sio, GPIO_PORT2_DEVICE);
set_enable(sio, 0);
/* disable gpio_port3 */
set_logical_device(sio, GPIO_PORT3_DEVICE);
set_enable(sio, 0);
/* disable acpi */
set_logical_device(sio, ACPI_DEVICE);
set_enable(sio, 0);
/* disable hw monitor */
set_logical_device(sio, HW_MONITOR_DEVICE);
set_enable(sio, 0);
#if 0
/* setup acpi registers so I am certain to get
* power on after power fail.
*/
setup_acpi_registers(sio);
#endif
write_config(sio, 1, 0x30);
exit_pnp(sio);
}
/* The base address is either 0x2e or 0x4e */
struct superio_control superio_winbond_w83627hf_control = {
(void *)0, enable_devices, (void *)0, 0x2e, "w83627hf"
};