summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile17
-rw-r--r--arch/ppc/kernel/apus_setup.c216
-rw-r--r--arch/ppc/kernel/chrp_pci.c15
-rw-r--r--arch/ppc/kernel/chrp_setup.c8
-rw-r--r--arch/ppc/kernel/chrp_time.c7
-rw-r--r--arch/ppc/kernel/entry.S27
-rw-r--r--arch/ppc/kernel/feature.c282
-rw-r--r--arch/ppc/kernel/galaxy_pci.c102
-rw-r--r--arch/ppc/kernel/gemini_setup.c21
-rw-r--r--arch/ppc/kernel/head.S81
-rw-r--r--arch/ppc/kernel/head_4xx.S32
-rw-r--r--arch/ppc/kernel/idle.c17
-rw-r--r--arch/ppc/kernel/irq.c4
-rw-r--r--arch/ppc/kernel/local_irq.h2
-rw-r--r--arch/ppc/kernel/misc.S30
-rw-r--r--arch/ppc/kernel/oak_setup.c57
-rw-r--r--arch/ppc/kernel/oak_setup.h6
-rw-r--r--arch/ppc/kernel/open_pic.c152
-rw-r--r--arch/ppc/kernel/pci-dma.c52
-rw-r--r--arch/ppc/kernel/pci.c2
-rw-r--r--arch/ppc/kernel/pmac_nvram.c33
-rw-r--r--arch/ppc/kernel/pmac_pci.c253
-rw-r--r--arch/ppc/kernel/pmac_pic.c226
-rw-r--r--arch/ppc/kernel/pmac_setup.c85
-rw-r--r--arch/ppc/kernel/pmac_time.c4
-rw-r--r--arch/ppc/kernel/ppc-stub.c2
-rw-r--r--arch/ppc/kernel/ppc_htab.c17
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c2
-rw-r--r--arch/ppc/kernel/prep_pci.c2
-rw-r--r--arch/ppc/kernel/process.c2
-rw-r--r--arch/ppc/kernel/prom.c625
-rw-r--r--arch/ppc/kernel/semaphore.c41
-rw-r--r--arch/ppc/kernel/setup.c54
-rw-r--r--arch/ppc/kernel/sleep.S5
-rw-r--r--arch/ppc/kernel/syscalls.c13
-rw-r--r--arch/ppc/kernel/traps.c14
-rw-r--r--arch/ppc/kernel/walnut_setup.c295
-rw-r--r--arch/ppc/kernel/walnut_setup.h50
38 files changed, 2312 insertions, 541 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 7aaacfadb..ea7c7c6e7 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -38,7 +38,7 @@ O_OBJS += hashtable.o
endif
ifdef CONFIG_PCI
-O_OBJS += pci.o
+O_OBJS += pci.o pci-dma.o
endif
ifdef CONFIG_KGDB
@@ -59,8 +59,16 @@ endif
ifeq ($(CONFIG_4xx),y)
O_OBJS += ppc4xx_pic.o
- ifeq ($(CONFIG_OAK),y)
- O_OBJS += oak_setup.o
+endif
+
+ifeq ($(CONFIG_OAK),y)
+ O_OBJS += oak_setup.o
+endif
+
+ifeq ($(CONFIG_WALNUT),y)
+ O_OBJS += walnut_setup.o
+ ifeq ($(CONFIG_PCI),y)
+ O_OBJS += galaxy_pci.o
endif
endif
@@ -83,6 +91,9 @@ endif
ifeq ($(CONFIG_6xx),y)
O_OBJS += open_pic.o indirect_pci.o
endif
+ifeq ($(CONFIG_PPC64),y)
+ O_OBJS += open_pic.o indirect_pci.o
+endif
ifeq ($(CONFIG_APUS),y)
O_OBJS += apus_setup.o
endif
diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c
index a7b057fa1..5f0c4b06e 100644
--- a/arch/ppc/kernel/apus_setup.c
+++ b/arch/ppc/kernel/apus_setup.c
@@ -19,7 +19,6 @@
#include <linux/sched.h>
#include <linux/kd.h>
#include <linux/init.h>
-#include <linux/serial.h>
#include <linux/hdreg.h>
#include <linux/blk.h>
#include <linux/pci.h>
@@ -28,8 +27,41 @@
#include <asm/logging.h>
#endif
-/* Get the IDE stuff from the 68k file */
#include <linux/ide.h>
+#define T_CHAR (0x0000) /* char: don't touch */
+#define T_SHORT (0x4000) /* short: 12 -> 21 */
+#define T_INT (0x8000) /* int: 1234 -> 4321 */
+#define T_TEXT (0xc000) /* text: 12 -> 21 */
+
+#define T_MASK_TYPE (0xc000)
+#define T_MASK_COUNT (0x3fff)
+
+#define D_CHAR(cnt) (T_CHAR | (cnt))
+#define D_SHORT(cnt) (T_SHORT | (cnt))
+#define D_INT(cnt) (T_INT | (cnt))
+#define D_TEXT(cnt) (T_TEXT | (cnt))
+
+static u_short driveid_types[] = {
+ D_SHORT(10), /* config - vendor2 */
+ D_TEXT(20), /* serial_no */
+ D_SHORT(3), /* buf_type, buf_size - ecc_bytes */
+ D_TEXT(48), /* fw_rev - model */
+ D_CHAR(2), /* max_multsect - vendor3 */
+ D_SHORT(1), /* dword_io */
+ D_CHAR(2), /* vendor4 - capability */
+ D_SHORT(1), /* reserved50 */
+ D_CHAR(4), /* vendor5 - tDMA */
+ D_SHORT(4), /* field_valid - cur_sectors */
+ D_INT(1), /* cur_capacity */
+ D_CHAR(2), /* multsect - multsect_valid */
+ D_INT(1), /* lba_capacity */
+ D_SHORT(194) /* dma_1word - reservedyy */
+};
+
+#define num_driveid_types (sizeof(driveid_types)/sizeof(*driveid_types))
+
+#if 0 /* Get rid of this crud */
+/* Get the IDE stuff from the 68k file */
#define ide_init_hwif_ports m68k_ide_init_hwif_ports
#define ide_default_irq m68k_ide_default_irq
#undef ide_request_irq
@@ -57,6 +89,7 @@
#undef ide_release_region
#undef ide_fix_driveid
/*-------------------------------------------*/
+#endif
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -411,33 +444,6 @@ void kbd_reset_setup(char *str, int *ints)
{
}
-#if defined(CONFIG_WHIPPET_SERIAL)||defined(CONFIG_MULTIFACE_III_TTY)||defined(CONFIG_GVPIOEXT)||defined(CONFIG_AMIGA_BUILTIN_SERIAL)
-
-long m68k_rs_init(void);
-int m68k_register_serial(struct serial_struct *);
-void m68k_unregister_serial(int);
-long m68k_serial_console_init(long, long );
-
-int rs_init(void)
-{
- return m68k_rs_init();
-}
-int register_serial(struct serial_struct *p)
-{
- return m68k_register_serial(p);
-}
-void unregister_serial(int i)
-{
- m68k_unregister_serial(i);
-}
-#ifdef CONFIG_SERIAL_CONSOLE
-long serial_console_init(long kmem_start, long kmem_end)
-{
- return m68k_serial_console_init(kmem_start, kmem_end);
-}
-#endif
-#endif
-
/*********************************************************** FLOPPY */
#if defined(CONFIG_AMIGA_FLOPPY)
__init
@@ -673,7 +679,7 @@ apus_ide_outsw(ide_ioreg_t port, void *buf, int ns)
int
apus_ide_default_irq(ide_ioreg_t base)
{
- return m68k_ide_default_irq(base);
+ return 0;
}
ide_ioreg_t
@@ -685,7 +691,7 @@ apus_ide_default_io_base(int index)
int
apus_ide_check_region(ide_ioreg_t from, unsigned int extent)
{
- return m68k_ide_check_region(from, extent);
+ return 0;
}
void
@@ -693,27 +699,66 @@ apus_ide_request_region(ide_ioreg_t from,
unsigned int extent,
const char *name)
{
- m68k_ide_request_region(from, extent, name);
}
void
apus_ide_release_region(ide_ioreg_t from,
unsigned int extent)
{
- m68k_ide_release_region(from, extent);
}
void
apus_ide_fix_driveid(struct hd_driveid *id)
{
- m68k_ide_fix_driveid(id);
+ u_char *p = (u_char *)id;
+ int i, j, cnt;
+ u_char t;
+
+ if (!MACH_IS_AMIGA && !MACH_IS_MAC)
+ return;
+ for (i = 0; i < num_driveid_types; i++) {
+ cnt = driveid_types[i] & T_MASK_COUNT;
+ switch (driveid_types[i] & T_MASK_TYPE) {
+ case T_CHAR:
+ p += cnt;
+ break;
+ case T_SHORT:
+ for (j = 0; j < cnt; j++) {
+ t = p[0];
+ p[0] = p[1];
+ p[1] = t;
+ p += 2;
+ }
+ break;
+ case T_INT:
+ for (j = 0; j < cnt; j++) {
+ t = p[0];
+ p[0] = p[3];
+ p[3] = t;
+ t = p[1];
+ p[1] = p[2];
+ p[2] = t;
+ p += 4;
+ }
+ break;
+ case T_TEXT:
+ for (j = 0; j < cnt; j += 2) {
+ t = p[0];
+ p[0] = p[1];
+ p[1] = t;
+ p += 2;
+ }
+ break;
+ }
+ }
}
__init
void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
ide_ioreg_t ctrl_port, int *irq)
{
- m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
+ if (data_port || ctrl_port)
+ printk("apus_ide_init_hwif_ports: must not be called\n");
}
#endif
/****************************************************** IRQ stuff */
@@ -732,7 +777,7 @@ int apus_get_irq_list(char *buf)
/* IPL must be between 0 and 7 */
__apus
-static inline void apus_set_IPL(int ipl)
+static inline void apus_set_IPL(unsigned long ipl)
{
APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
@@ -743,42 +788,22 @@ static inline void apus_set_IPL(int ipl)
__apus
static inline unsigned long apus_get_IPL(void)
{
- unsigned short __f;
+ /* This returns the present IPL emulation level. */
+ unsigned long __f;
APUS_READ(APUS_IPL_EMU, __f);
return ((~__f) & IPLEMU_IPLMASK);
}
__apus
-static inline unsigned long apus_get_prev_IPL(void)
-{
- unsigned short __f;
- APUS_READ(APUS_IPL_EMU, __f);
- return ((~__f >> 3) & IPLEMU_IPLMASK);
-}
-
-
-__apus
-static void apus_save_flags(unsigned long* flags)
+static inline unsigned long apus_get_prev_IPL(struct pt_regs* regs)
{
- *flags = apus_get_IPL();
-}
-
-__apus
-static void apus_restore_flags(unsigned long flags)
-{
- apus_set_IPL(flags);
-}
-
-__apus
-static void apus_sti(void)
-{
- apus_set_IPL(0);
-}
-
-__apus
-static void apus_cli(void)
-{
- apus_set_IPL(7);
+ /* The value saved in mq is the IPL_EMU value at the time of
+ interrupt. The lower bits are the current interrupt level,
+ the upper bits the requested level. Thus, to restore the
+ IPL level to the post-interrupt state, we will need to use
+ the lower bits. */
+ unsigned long __f = regs->mq;
+ return ((~__f) & IPLEMU_IPLMASK);
}
@@ -802,6 +827,22 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
return amiga_request_irq (irq, handler, irqflags, devname, dev_id);
}
+
+/* In Linux/m68k the sys_request_irq deals with vectors 0-7. That's what
+ callers expect - but on Linux/APUS we actually use the IRQ_AMIGA_AUTO
+ vectors (24-31), so we put this dummy function in between to adjust
+ the vector argument (rather have cruft here than in the generic irq.c). */
+int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
+{
+ extern int request_sysirq(unsigned int irq,
+ void (*handler)(int, void *,
+ struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname, void *dev_id);
+ return request_sysirq(irq+IRQ_AMIGA_AUTO, handler, irqflags,
+ devname, dev_id);
+}
#endif
__apus
@@ -809,14 +850,17 @@ int apus_get_irq(struct pt_regs* regs)
{
#ifdef CONFIG_APUS
int level = apus_get_IPL();
- unsigned short ints = custom.intreqr & custom.intenar;
+
+#ifdef __INTERRUPT_DEBUG
+ printk("<%d:%d>", level, apus_get_prev_IPL(regs));
+#endif
if (0 == level)
- return -1;
+ return -8;
if (7 == level)
- return -2;
+ return -9;
- return level;
+ return level + IRQ_AMIGA_AUTO;
#else
return 0;
#endif
@@ -824,10 +868,13 @@ int apus_get_irq(struct pt_regs* regs)
__apus
-void apus_post_irq(int level)
+void apus_post_irq(struct pt_regs* regs, int level)
{
+#ifdef __INTERRUPT_DEBUG
+ printk("{%d}", apus_get_prev_IPL(regs));
+#endif
/* Restore IPL to the previous value */
- apus_set_IPL(apus_get_IPL());
+ apus_set_IPL(apus_get_prev_IPL(regs));
}
@@ -903,11 +950,28 @@ irq_node_t *new_irq_node(void)
return NULL;
}
+extern void amiga_enable_irq(unsigned int irq);
+extern void amiga_disable_irq(unsigned int irq);
+
+struct hw_interrupt_type amiga_irqctrl = {
+ " Amiga ",
+ NULL,
+ NULL,
+ amiga_enable_irq,
+ amiga_disable_irq,
+ 0,
+ 0
+};
+
+
__init
void apus_init_IRQ(void)
{
int i;
+ for ( i = 0 ; i < NR_IRQS ; i++ )
+ irq_desc[i].ctl = &amiga_irqctrl;
+
for (i = 0; i < NUM_IRQ_NODES; i++)
nodes[i].handler = NULL;
@@ -919,10 +983,10 @@ void apus_init_IRQ(void)
amiga_init_IRQ();
- int_control.int_sti = apus_sti;
- int_control.int_cli = apus_cli;
- int_control.int_save_flags = apus_save_flags;
- int_control.int_restore_flags = apus_restore_flags;
+ int_control.int_sti = __no_use_sti;
+ int_control.int_cli = __no_use_cli;
+ int_control.int_save_flags = __no_use_save_flags;
+ int_control.int_restore_flags = __no_use_restore_flags;
}
__init
diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c
index b93bc45f7..a2fbe5f14 100644
--- a/arch/ppc/kernel/chrp_pci.c
+++ b/arch/ppc/kernel/chrp_pci.c
@@ -273,14 +273,13 @@ void __init
chrp_pcibios_fixup(void)
{
struct pci_dev *dev;
-
- /* some of IBM chrps have > 1 bus */
- if ( !strncmp("IBM", get_property(find_path_device("/"),
- "name", NULL),3) )
- {
-
- }
-
+ int i;
+ extern struct pci_ops generic_pci_ops;
+
+ /* Some IBM's with the python have >1 bus, this finds them */
+ for ( i = 0; i < python_busnr ; i++ )
+ pci_scan_bus(i+1, &generic_pci_ops, NULL);
+
/* PCI interrupts are controlled by the OpenPIC */
pci_for_each_dev(dev) {
if ( dev->irq )
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
index e76aa8dd9..21abfc84f 100644
--- a/arch/ppc/kernel/chrp_setup.c
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -249,7 +249,6 @@ chrp_setup_arch(void)
else
#endif
ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
-sprintf(cmd_line, "console=ttyS0,9600 console=tty0");
printk("Boot arguments: %s\n", cmd_line);
request_region(0x20,0x20,"pic1");
@@ -384,7 +383,7 @@ int chrp_get_irq( struct pt_regs *regs )
return irq;
}
-void chrp_post_irq(int irq)
+void chrp_post_irq(struct pt_regs* regs, int irq)
{
/*
* If it's an i8259 irq then we've already done the
@@ -394,7 +393,7 @@ void chrp_post_irq(int irq)
* We do it this way since our irq_desc[irq].handler can change
* with RTL and no longer be open_pic -- Cort
*/
- if ( irq >= open_pic.irq_offset)
+ if ( irq >= open_pic_irq_offset)
openpic_eoi( smp_processor_id() );
}
@@ -411,10 +410,11 @@ void __init chrp_init_IRQ(void)
(*(unsigned long *)get_property(np,
"8259-interrupt-acknowledge", NULL));
}
- open_pic.irq_offset = 16;
+ open_pic_irq_offset = 16;
for ( i = 16 ; i < NR_IRQS ; i++ )
irq_desc[i].handler = &open_pic;
openpic_init(1);
+ enable_irq(IRQ_8259_CASCADE);
for ( i = 0 ; i < 16 ; i++ )
irq_desc[i].handler = &i8259_pic;
i8259_init();
diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
index 50c7417fb..d55fa24c0 100644
--- a/arch/ppc/kernel/chrp_time.c
+++ b/arch/ppc/kernel/chrp_time.c
@@ -171,9 +171,10 @@ void __init chrp_calibrate_decr(void)
if (fp != 0)
freq = *fp;
}
- freq *= 60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %lu/%d\n", freq, divisor);
+ freq *= 30;
+ divisor = 30;
+ printk("time_init: decrementer frequency = %lu/%d (%d MHz)\n", freq,
+ divisor, (freq/divisor)>>20);
decrementer_count = freq / HZ / divisor;
count_period_num = divisor;
count_period_den = freq / 1000000;
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 2c4ff5554..2d1238a6b 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -256,6 +256,15 @@ _GLOBAL(_switch)
REST_8GPRS(23, r1)
REST_GPR(31, r1)
lwz r2,_NIP(r1) /* Restore environment */
+ /*
+ * We need to hard disable here even if RTL is active since
+ * being interrupted after here trashes SRR{0,1}
+ * -- Cort
+ */
+ mfmsr r0 /* Get current interrupt state */
+ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */
+ mtmsr r0 /* Update machine state */
+
lwz r0,_MSR(r1)
mtspr SRR0,r2
mtspr SRR1,r0
@@ -271,7 +280,7 @@ ret_from_smpfork:
bl schedule_tail
b ret_from_except
#endif
-
+
.globl ret_from_intercept
ret_from_intercept:
/*
@@ -291,7 +300,7 @@ ret_from_intercept:
.globl ret_from_except
ret_from_except:
-0: /* disable interrupts */
+0: /* disable interrupts */
lis r30,int_control@h
ori r30,r30,int_control@l
lwz r30,0(r30)
@@ -342,16 +351,26 @@ do_bottom_half_ret:
.globl do_signal_ret
do_signal_ret:
b 0b
-8: addi r4,r1,INT_FRAME_SIZE /* size of frame */
+8: /*
+ * We need to hard disable here even if RTL is active since
+ * being interrupted after here trashes the SPRG2
+ * -- Cort
+ */
+ mfmsr r0 /* Get current interrupt state */
+ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */
+ mtmsr r0 /* Update machine state */
+
+ addi r4,r1,INT_FRAME_SIZE /* size of frame */
stw r4,THREAD+KSP(r2) /* save kernel stack pointer */
tophys(r3,r1)
mtspr SPRG2,r3 /* phys exception stack pointer */
+ b 11f
10: /* make sure we hard disable here, even if rtl is active -- Cort */
mfmsr r0 /* Get current interrupt state */
rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */
sync /* Some chip revs have problems here... */
mtmsr r0 /* Update machine state */
-
+11:
lwz r2,_CTR(r1)
lwz r0,_LINK(r1)
mtctr r2
diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c
index a9a30396a..156eb187e 100644
--- a/arch/ppc/kernel/feature.c
+++ b/arch/ppc/kernel/feature.c
@@ -8,85 +8,144 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
+ * BenH: Changed implementation to work on multiple registers
+ * polarity is also taken into account. Removed delay (now
+ * responsibility of the caller). Added spinlocks.
+ *
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/spinlock.h>
#include <asm/errno.h>
#include <asm/ohare.h>
+#include <asm/heathrow.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/feature.h>
-#define MAX_FEATURE_REGS 2
#undef DEBUG_FEATURE
-static u32 feature_bits_pbook[] = {
- 0, /* FEATURE_null */
- OH_SCC_RESET, /* FEATURE_Serial_reset */
- OH_SCC_ENABLE, /* FEATURE_Serial_enable */
- OH_SCCA_IO, /* FEATURE_Serial_IO_A */
- OH_SCCB_IO, /* FEATURE_Serial_IO_B */
- OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */
- OH_MESH_ENABLE, /* FEATURE_MESH_enable */
- OH_IDE_ENABLE, /* FEATURE_IDE_enable */
- OH_VIA_ENABLE, /* FEATURE_VIA_enable */
- OH_IDECD_POWER, /* FEATURE_CD_power */
- OH_BAY_RESET, /* FEATURE_Mediabay_reset */
- OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */
- OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */
- OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */
- OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
- 0, /* FEATURE_BMac_reset */
- 0, /* FEATURE_BMac_IO_enable */
- 0, /* FEATURE_Modem_Reset -> guess... */
- OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */
- OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */
+#define MAX_FEATURE_CONTROLLERS 2
+#define MAX_FEATURE_OFFSET 0x50
+#define FREG(c,r) (&(((c)->reg)[(r)>>2]))
+
+typedef struct feature_bit {
+ int reg; /* reg. offset from mac-io base */
+ unsigned int polarity; /* 0 = normal, 1 = inverse */
+ unsigned int mask; /* bit mask */
+} fbit;
+
+/* I don't have an OHare machine to test with, so I left those as they
+ * were. Someone with such a machine chould check out what OF says and
+ * try too see if they match the heathrow ones and should be changed too
+ */
+static fbit feature_bits_ohare_pbook[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,OH_SCC_RESET}, /* FEATURE_Serial_reset */
+ {0x38,0,OH_SCC_ENABLE}, /* FEATURE_Serial_enable */
+ {0x38,0,OH_SCCA_IO}, /* FEATURE_Serial_IO_A */
+ {0x38,0,OH_SCCB_IO}, /* FEATURE_Serial_IO_B */
+ {0x38,0,OH_FLOPPY_ENABLE}, /* FEATURE_SWIM3_enable */
+ {0x38,0,OH_MESH_ENABLE}, /* FEATURE_MESH_enable */
+ {0x38,0,OH_IDE0_ENABLE}, /* FEATURE_IDE0_enable */
+ {0x38,1,OH_IDE0_RESET_N}, /* FEATURE_IDE0_reset */
+ {0x38,0,OH_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */
+ {0x38,1,OH_BAY_RESET_N}, /* FEATURE_Mediabay_reset */
+ {0x38,1,OH_BAY_POWER_N}, /* FEATURE_Mediabay_power */
+ {0x38,0,OH_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,OH_BAY_IDE_ENABLE}, /* FEATURE_Mediabay_IDE_enable */
+ {0x38,1,OH_IDE1_RESET_N}, /* FEATURE_Mediabay_IDE_reset */
+ {0x38,0,OH_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,0}, /* FEATURE_BMac_reset */
+ {0x38,0,0}, /* FEATURE_BMac_IO_enable */
+ {0x38,0,0}, /* FEATURE_Modem_power */
+ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,0,0}, /* FEATURE_Sound_Power */
+ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x38,0,0}, /* FEATURE_IDE2_reset */
};
-/* assume these are the same as the ohare until proven otherwise */
-static u32 feature_bits_heathrow[] = {
- 0, /* FEATURE_null */
- OH_SCC_RESET, /* FEATURE_Serial_reset */
- OH_SCC_ENABLE, /* FEATURE_Serial_enable */
- OH_SCCA_IO, /* FEATURE_Serial_IO_A */
- OH_SCCB_IO, /* FEATURE_Serial_IO_B */
- OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */
- OH_MESH_ENABLE, /* FEATURE_MESH_enable */
- OH_IDE_ENABLE, /* FEATURE_IDE_enable */
- OH_VIA_ENABLE, /* FEATURE_VIA_enable */
- OH_IDECD_POWER, /* FEATURE_CD_power */
- OH_BAY_RESET, /* FEATURE_Mediabay_reset */
- OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */
- OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */
- OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */
- OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
- 0x80000000, /* FEATURE_BMac_reset */
- 0x60000000, /* FEATURE_BMac_IO_enable */
- 0x02000000, /* FEATURE_Modem_Reset -> guess...*/
- OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */
- OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */
+/* Those bits are from a PowerBook. It's possible that desktop machines
+ * based on heathrow need a different definition or some bits removed
+ */
+static fbit feature_bits_heathrow[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */
+ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */
+ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */
+ {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */
+ {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */
+ {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */
+ {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */
+ {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */
+ {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */
+ {0x38,1,HRW_BAY_RESET_N}, /* FEATURE_Mediabay_reset */
+ {0x38,1,HRW_BAY_POWER_N}, /* FEATURE_Mediabay_power */
+ {0x38,0,HRW_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_Mediabay_IDE_enable */
+ {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_Mediabay_IDE_reset */
+ {0x38,0,HRW_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */
+ {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */
+ {0x38,1,HRW_MODEM_POWER_N}, /* FEATURE_Modem_power */
+ {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,1,HRW_SOUND_POWER_N}, /* FEATURE_Sound_Power */
+ {0x38,0,HRW_SOUND_CLK_ENABLE}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x38,0,0}, /* FEATURE_IDE2_reset */
+};
+
+/* Those bits are from an iBook.
+ */
+static fbit feature_bits_keylargo[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,0}, /* FEATURE_Serial_reset */
+ {0x38,0,0x00000054}, /* FEATURE_Serial_enable */
+ {0x38,0,0}, /* FEATURE_Serial_IO_A */
+ {0x38,0,0}, /* FEATURE_Serial_IO_B */
+ {0x38,0,0}, /* FEATURE_SWIM3_enable */
+ {0x38,0,0}, /* FEATURE_MESH_enable */
+ {0x38,0,0}, /* FEATURE_IDE0_enable */
+ {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */
+ {0x38,0,0}, /* FEATURE_IOBUS_enable */
+ {0x38,0,0}, /* FEATURE_Mediabay_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_power */
+ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,0}, /* FEATURE_Mediabay_IDE_enable */
+ {0x3c,1,0x08000000}, /* FEATURE_Mediabay_IDE_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,0}, /* FEATURE_BMac_reset */
+ {0x38,0,0}, /* FEATURE_BMac_IO_enable */
+ {0x40,1,0x02000000}, /* FEATURE_Modem_power */
+ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,0,0}, /* FEATURE_Sound_Power */
+ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */
};
/* definition of a feature controller object */
-struct feature_controller
-{
- u32* bits;
+struct feature_controller {
+ fbit* bits;
volatile u32* reg;
struct device_node* device;
+ spinlock_t lock;
};
/* static functions */
static void
-feature_add_controller(struct device_node *controller_device, u32* bits);
+feature_add_controller(struct device_node *controller_device, fbit* bits);
-static int
+static struct feature_controller*
feature_lookup_controller(struct device_node *device);
/* static varialbles */
-static struct feature_controller controllers[MAX_FEATURE_REGS];
+static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS];
static int controller_count = 0;
@@ -96,18 +155,23 @@ feature_init(void)
struct device_node *np;
np = find_devices("mac-io");
- while (np != NULL)
- {
- feature_add_controller(np, feature_bits_heathrow);
+ while (np != NULL) {
+ /* KeyLargo contains several (5 ?) FCR registers in mac-io,
+ * plus some gpio's which could eventually be handled here.
+ */
+ if (device_is_compatible(np, "Keylargo")) {
+ feature_add_controller(np, feature_bits_keylargo);
+ } else {
+ feature_add_controller(np, feature_bits_heathrow);
+ }
np = np->next;
}
if (controller_count == 0)
{
np = find_devices("ohare");
- if (np)
- {
+ if (np) {
if (find_devices("via-pmu") != NULL)
- feature_add_controller(np, feature_bits_pbook);
+ feature_add_controller(np, feature_bits_ohare_pbook);
else
/* else not sure; maybe this is a Starmax? */
feature_add_controller(np, NULL);
@@ -116,17 +180,26 @@ feature_init(void)
if (controller_count)
printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
+
+#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_DMASOUND_MODULE
+ /* On PowerBooks, we disable the sound chip when dmasound is a module */
+ if (controller_count && find_devices("via-pmu") != NULL) {
+ feature_clear(controllers[0].device, FEATURE_Sound_power);
+ feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable);
+ }
+#endif
+#endif
}
static void
-feature_add_controller(struct device_node *controller_device, u32* bits)
+feature_add_controller(struct device_node *controller_device, fbit* bits)
{
struct feature_controller* controller;
- if (controller_count >= MAX_FEATURE_REGS)
- {
+ if (controller_count >= MAX_FEATURE_CONTROLLERS) {
printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
- controller_device->full_name, MAX_FEATURE_REGS);
+ controller_device->full_name, MAX_FEATURE_CONTROLLERS);
return;
}
controller = &controllers[controller_count];
@@ -140,30 +213,32 @@ feature_add_controller(struct device_node *controller_device, u32* bits)
}
controller->reg = (volatile u32 *)ioremap(
- controller_device->addrs[0].address + OHARE_FEATURE_REG, 4);
+ controller_device->addrs[0].address, MAX_FEATURE_OFFSET);
if (bits == NULL) {
printk(KERN_INFO "Twiddling the magic ohare bits\n");
- out_le32(controller->reg, STARMAX_FEATURES);
+ out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES);
return;
}
+ spin_lock_init(&controller->lock);
+
controller_count++;
}
-static int
+static struct feature_controller*
feature_lookup_controller(struct device_node *device)
{
int i;
if (device == NULL)
- return -EINVAL;
+ return NULL;
while(device)
{
for (i=0; i<controller_count; i++)
if (device == controllers[i].device)
- return i;
+ return &controllers[i];
device = device->parent;
}
@@ -172,35 +247,36 @@ feature_lookup_controller(struct device_node *device)
device->name);
#endif
- return -ENODEV;
+ return NULL;
}
int
feature_set(struct device_node* device, enum system_feature f)
{
- int controller;
- unsigned long flags;
+ struct feature_controller* controller;
+ unsigned long flags;
+ unsigned long value;
+ fbit* bit;
if (f >= FEATURE_last)
return -EINVAL;
controller = feature_lookup_controller(device);
- if (controller < 0)
- return controller;
+ if (!controller)
+ return -ENODEV;
+ bit = &controller->bits[f];
#ifdef DEBUG_FEATURE
printk("feature: <%s> setting feature %d in controller @0x%x\n",
- device->name, (int)f, (unsigned int)controllers[controller].reg);
+ device->name, (int)f, (unsigned int)controller->reg);
#endif
- save_flags(flags);
- cli();
- out_le32( controllers[controller].reg,
- in_le32(controllers[controller].reg) |
- controllers[controller].bits[f]);
- (void)in_le32(controllers[controller].reg);
- restore_flags(flags);
- udelay(10);
+ spin_lock_irqsave(&controller->lock, flags);
+ value = in_le32(FREG(controller, bit->reg));
+ value = bit->polarity ? (value & ~bit->mask) : (value | bit->mask);
+ out_le32(FREG(controller, bit->reg), value);
+ (void)in_le32(FREG(controller, bit->reg));
+ spin_unlock_irqrestore(&controller->lock, flags);
return 0;
}
@@ -208,29 +284,30 @@ feature_set(struct device_node* device, enum system_feature f)
int
feature_clear(struct device_node* device, enum system_feature f)
{
- int controller;
- unsigned long flags;
+ struct feature_controller* controller;
+ unsigned long flags;
+ unsigned long value;
+ fbit* bit;
if (f >= FEATURE_last)
return -EINVAL;
controller = feature_lookup_controller(device);
- if (controller < 0)
- return controller;
+ if (!controller)
+ return -ENODEV;
+ bit = &controller->bits[f];
#ifdef DEBUG_FEATURE
printk("feature: <%s> clearing feature %d in controller @0x%x\n",
- device->name, (int)f, (unsigned int)controllers[controller].reg);
+ device->name, (int)f, (unsigned int)controller->reg);
#endif
- save_flags(flags);
- cli();
- out_le32( controllers[controller].reg,
- in_le32(controllers[controller].reg) &
- ~(controllers[controller].bits[f]));
- (void)in_le32(controllers[controller].reg);
- restore_flags(flags);
- udelay(10);
+ spin_lock_irqsave(&controller->lock, flags);
+ value = in_le32(FREG(controller, bit->reg));
+ value = bit->polarity ? (value | bit->mask) : (value & ~bit->mask);
+ out_le32(FREG(controller, bit->reg), value);
+ (void)in_le32(FREG(controller, bit->reg));
+ spin_unlock_irqrestore(&controller->lock, flags);
return 0;
}
@@ -238,16 +315,27 @@ feature_clear(struct device_node* device, enum system_feature f)
int
feature_test(struct device_node* device, enum system_feature f)
{
- int controller;
+ struct feature_controller* controller;
+ unsigned long value;
+ fbit* bit;
if (f >= FEATURE_last)
return -EINVAL;
controller = feature_lookup_controller(device);
- if (controller < 0)
- return controller;
+ if (!controller)
+ return -ENODEV;
+ bit = &controller->bits[f];
- return (in_le32(controllers[controller].reg) &
- controllers[controller].bits[f]) != 0;
+#ifdef DEBUG_FEATURE
+ printk("feature: <%s> clearing feature %d in controller @0x%x\n",
+ device->name, (int)f, (unsigned int)controller->reg);
+#endif
+ /* If one feature contains several bits, all of them must be set
+ * for value to be true, or all of them must be 0 if polarity is
+ * inverse
+ */
+ value = (in_le32(FREG(controller, bit->reg)) & bit->mask);
+ return bit->polarity ? (value == 0) : (value == bit->mask);
}
diff --git a/arch/ppc/kernel/galaxy_pci.c b/arch/ppc/kernel/galaxy_pci.c
new file mode 100644
index 000000000..aeddd9a0e
--- /dev/null
+++ b/arch/ppc/kernel/galaxy_pci.c
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright (c) 2000 Grant Erickson <grant@borg.umn.edu>
+ * All rights reserved.
+ *
+ * Module name: galaxy_pci.c
+ *
+ * Description:
+ * PCI interface code for the IBM PowerPC 405GP on-chip PCI bus
+ * interface.
+ *
+ * Why is this file called "galaxy_pci"? Because on the original
+ * IBM "Walnut" evaluation board schematic I have, the 405GP is
+ * is labeled "GALAXY".
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
+
+
+/* Preprocessor Defines */
+
+#define PCICFGADDR (volatile unsigned int *)(0xEEC00000)
+#define PCICFGDATA (volatile unsigned int *)(0xEEC00004)
+
+
+/* Function Prototypes */
+
+decl_config_access_method(galaxy);
+
+
+void __init
+galaxy_pcibios_fixup(void)
+{
+
+}
+
+void __init
+galaxy_setup_pci_ptrs(void)
+{
+ set_config_access_method(galaxy);
+
+ ppc_md.pcibios_fixup = galaxy_pcibios_fixup;
+}
+
+int
+galaxy_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+
+ return (PCIBIOS_SUCCESSFUL);
+}
+
+int
+galaxy_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+
+ return (PCIBIOS_SUCCESSFUL);
+}
+
+int
+galaxy_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+
+ return (PCIBIOS_SUCCESSFUL);
+}
+
+int
+galaxy_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+
+ return (PCIBIOS_SUCCESSFUL);
+}
+
+int
+galaxy_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+
+ return (PCIBIOS_SUCCESSFUL);
+}
+
+int
+galaxy_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+
+ return (PCIBIOS_SUCCESSFUL);
+}
diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c
index d7ca91780..fcf3a701c 100644
--- a/arch/ppc/kernel/gemini_setup.c
+++ b/arch/ppc/kernel/gemini_setup.c
@@ -53,7 +53,7 @@ static unsigned int cpu_6xx[16] = {
};
int chrp_get_irq(struct pt_regs *);
-void chrp_post_irq(int);
+void chrp_post_irq(struct pt_regs* regs, int);
static inline unsigned long _get_HID1(void)
{
@@ -132,6 +132,19 @@ extern unsigned long loops_per_sec;
extern int root_mountflags;
extern char cmd_line[];
+void
+gemini_heartbeat(void)
+{
+ static unsigned long led = GEMINI_LEDBASE+(4*8);
+ static char direction = 8;
+ *(char *)led = 0;
+ if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) ||
+ (led + direction) < (GEMINI_LEDBASE+(4*8)) )
+ direction *= -1;
+ led += direction;
+ *(char *)led = 0xff;
+ ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+}
void __init gemini_setup_arch(void)
{
@@ -175,6 +188,10 @@ void __init gemini_setup_arch(void)
printk("CPU manufacturer: %s [rev=%04x]\n", (cpu & (1<<15)) ? "IBM" :
"Motorola", (cpu & 0xffff));
+ ppc_md.heartbeat = gemini_heartbeat;
+ ppc_md.heartbeat_reset = HZ/8;
+ ppc_md.heartbeat_count = 1;
+
/* take special pains to map the MPIC, since it isn't mapped yet */
gemini_openpic_init();
/* start the L2 */
@@ -505,7 +522,7 @@ int gemini_get_irq( struct pt_regs *regs )
return irq;
}
-void gemini_post_irq(int irq)
+void gemini_post_irq(struct pt_regs* regs, int irq)
{
/*
* If it's an i8259 irq then we've already done the
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index a70ba8bfd..8b56c635c 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -156,6 +156,16 @@ __start:
bl fix_mem_constants
#endif /* CONFIG_APUS */
+#ifndef CONFIG_GEMINI
+/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
+ * the physical address we are running at, returned by prom_init()
+ */
+__after_prom_start:
+ bl mmu_off
+ bl clear_bats
+ bl flush_tlbs
+#endif
+
/*
* Use the first pair of BAT registers to map the 1st 16MB
* of RAM to KERNELBASE. From this point on we can't safely
@@ -211,6 +221,11 @@ __start:
mtspr DBAT0U,r11 /* bit in upper BAT register */
mtspr IBAT0L,r8
mtspr IBAT0U,r11
+#if 0 /* Useful debug code, please leave in for now so I don't have to
+ * look at docs when I need to setup a BAT ;
+ */
+ bl setup_screen_bat
+#endif
5: isync
#ifndef CONFIG_APUS
@@ -627,12 +642,8 @@ DataStoreTLBMiss:
mtcrf 0x80,r3
rfi
-/* Instruction address breakpoint exception (on 603/604) */
STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
-
-/* System management exception (603?) */
- STD_EXCEPTION(0x1400, Trap_14, UnknownException)
-
+ STD_EXCEPTION(0x1400, SMI, SMIException)
STD_EXCEPTION(0x1500, Trap_15, UnknownException)
STD_EXCEPTION(0x1600, Trap_16, UnknownException)
STD_EXCEPTION(0x1700, Trap_17, TAUException)
@@ -644,10 +655,7 @@ DataStoreTLBMiss:
STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
-
- /* Run mode exception */
STD_EXCEPTION(0x2000, RunMode, RunModeException)
-
STD_EXCEPTION(0x2100, Trap_21, UnknownException)
STD_EXCEPTION(0x2200, Trap_22, UnknownException)
STD_EXCEPTION(0x2300, Trap_23, UnknownException)
@@ -911,12 +919,16 @@ giveup_fpu:
* the kernel image to physical address 0.
*/
relocate_kernel:
+#if 0 /* Is this still needed ? I don't think so. It breaks new
+ * boot-with-mmu-off stuff
+ */
lis r9,0x426f /* if booted from BootX, don't */
addi r9,r9,0x6f58 /* translate source addr */
cmpw r31,r9 /* (we have to on chrp) */
beq 7f
rlwinm r4,r4,0,8,31 /* translate source address */
add r4,r4,r3 /* to region mapped with BATs */
+#endif
7: addis r9,r26,klimit@ha /* fetch klimit */
lwz r25,klimit@l(r9)
addis r25,r25,-KERNELBASE@h
@@ -1194,14 +1206,26 @@ enable_caches:
cmpi 0,r9,4 /* check for 604 */
cmpi 1,r9,9 /* or 604e */
cmpi 2,r9,10 /* or mach5 */
+ cmpi 3,r9,8 /* check for 750 (G3) */
+ cmpi 4,r9,12 /* or 7400 (G4) */
cror 2,2,6
cror 2,2,10
bne 4f
ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
bne 2,5f
ori r11,r11,HID0_BTCD
+ b 5f
+4:
+ cror 14,14,18
+ bne 3,6f
+ /* We should add ABE here if we want to use Store Gathering
+ * and other nifty bridge features
+ */
+ ori r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC /* for g3/g4, enable */
+ li r3,0
+ mtspr ICTC,r3
5: mtspr HID0,r11 /* superscalar exec & br history tbl */
-4: blr
+6: blr
/*
* Load stuff into the MMU. Intended to be called with
@@ -1388,6 +1412,45 @@ clear_bats:
#endif /* !defined(CONFIG_GEMINI) */
blr
+#ifndef CONFIG_GEMINI
+flush_tlbs:
+ lis r20, 0x1000
+1: addic. r20, r20, -0x1000
+ tlbie r20
+ blt 1b
+ sync
+ blr
+
+mmu_off:
+ addi r4, r3, __after_prom_start - _start
+ mfmsr r3
+ andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */
+ beq 1f
+ ori r3,r3,MSR_DR|MSR_IR
+ xori r3,r3,MSR_DR|MSR_IR
+ mtspr SRR0,r4
+ mtspr SRR1,r3
+ sync
+ rfi
+1: blr
+#endif
+
+#if 0 /* That's useful debug stuff */
+setup_screen_bat:
+ lis r3, 0x9100
+#ifdef __SMP__
+ ori r3,r3,0x12
+#else
+ ori r3,r3,0x2
+#endif
+ mtspr DBAT1L, r3
+ mtspr IBAT1L, r3
+ ori r3,r3,(BL_8M<<2)|0x2 /* set up BAT registers for 604 */
+ mtspr DBAT1U, r3
+ mtspr IBAT1U, r3
+ blr
+#endif
+
/*
* We put a few things here that have to be page-aligned.
* This stuff goes at the beginning of the data segment,
diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
index ba3284ad8..bec805b92 100644
--- a/arch/ppc/kernel/head_4xx.S
+++ b/arch/ppc/kernel/head_4xx.S
@@ -78,13 +78,17 @@ _GLOBAL(_start)
li r24,0
+ ## Invalidate all TLB entries
+
+ tlbia
+
## We should still be executing code at physical address 0x0000xxxx
## at this point. However, start_here is at virtual address
## 0xC000xxxx. So, set up a TLB mapping to cover this once
## translation is enabled.
lis r3,KERNELBASE@h # Load the kernel virtual address
- addis r3,r3,KERNELBASE@l
+ ori r3,r3,KERNELBASE@l
tophys(r4,r3) # Load the kernel physical address
## Save the existing PID and load the kernel PID.
@@ -96,11 +100,7 @@ _GLOBAL(_start)
## Configure and load entry into TLB slot 0.
clrrwi r4,r4,10 # Mask off the real page number
-
- ## XXX - Temporarily set the TLB_I bit because of cache issues that
- ## seem to foul-up the exception handling code.
-
- ori r4,r4,(TLB_WR | TLB_EX | TLB_I) # Set the write and execute bits
+ ori r4,r4,(TLB_WR | TLB_EX) # Set the write and execute bits
clrrwi r3,r3,10 # Mask off the effective page number
ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
@@ -333,22 +333,12 @@ _GLOBAL(timer_interrupt_intercept)
#endif
### 0x1100 - Data TLB Miss Exception
-
- START_EXCEPTION(0x1100, DTLBMiss)
- STND_EXCEPTION_PROLOG
- addi r3,r1,STACK_FRAME_OVERHEAD
- li r7,STND_EXC
- li r20,MSR_KERNEL
- FINISH_EXCEPTION(UnknownException)
+
+ STND_EXCEPTION(0x1100, DTLBMiss, PPC4xx_dtlb_miss)
### 0x1200 - Instruction TLB Miss Exception
-
- START_EXCEPTION(0x1200, ITLBMiss)
- STND_EXCEPTION_PROLOG
- addi r3,r1,STACK_FRAME_OVERHEAD
- li r7,STND_EXC
- li r20,MSR_KERNEL
- FINISH_EXCEPTION(UnknownException)
+
+ STND_EXCEPTION(0x1200, ITLBMiss, PPC4xx_itlb_miss)
STND_EXCEPTION(0x1300, Trap_13, UnknownException)
STND_EXCEPTION(0x1400, Trap_14, UnknownException)
@@ -560,8 +550,6 @@ start_here:
_GLOBAL(set_context)
mtspr SPRN_PID,r3
- tlbia
- SYNC
blr
###
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index 8dda6ad6b..7cf97b873 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -154,11 +154,12 @@ unsigned long get_zero_page_fast(void)
if ( zero_quicklist )
{
/* atomically remove this page from the list */
- asm ( "101:lwarx %1,0,%2\n" /* reserve zero_cache */
+ register unsigned long tmp;
+ asm ( "101:lwarx %1,0,%3\n" /* reserve zero_cache */
" lwz %0,0(%1)\n" /* get next -- new zero_cache */
- " stwcx. %0,0,%2\n" /* update zero_cache */
+ " stwcx. %0,0,%3\n" /* update zero_cache */
" bne- 101b\n" /* if lost reservation try again */
- : "=&r" (zero_quicklist), "=&r" (page)
+ : "=&r" (tmp), "=&r" (page), "+m" (zero_cache)
: "r" (&zero_quicklist)
: "cc" );
#ifdef __SMP__
@@ -193,6 +194,7 @@ void zero_paged(void)
{
unsigned long pageptr = 0; /* current page being zero'd */
unsigned long bytecount = 0;
+ register unsigned long tmp;
pte_t *pte;
if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
@@ -249,15 +251,14 @@ void zero_paged(void)
pte_cache(*pte);
flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
/* atomically add this page to the list */
- asm ( "101:lwarx %0,0,%1\n" /* reserve zero_cache */
- " stw %0,0(%2)\n" /* update *pageptr */
+ asm ( "101:lwarx %0,0,%2\n" /* reserve zero_cache */
+ " stw %0,0(%3)\n" /* update *pageptr */
#ifdef __SMP__
" sync\n" /* let store settle */
#endif
- " mr %0,%2\n" /* update zero_cache in reg */
- " stwcx. %2,0,%1\n" /* update zero_cache in mem */
+ " stwcx. %3,0,%2\n" /* update zero_cache in mem */
" bne- 101b\n" /* if lost reservation try again */
- : "=&r" (zero_quicklist)
+ : "=&r" (tmp), "+m" (zero_quicklist)
: "r" (&zero_quicklist), "r" (pageptr)
: "cc" );
/*
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index c2f2d1c11..8b5f590fb 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -126,7 +126,7 @@ void irq_kfree(void *ptr)
*/
int request_8xxirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
#elif defined(CONFIG_APUS)
-int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+int request_sysirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
#else
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
#endif
@@ -315,7 +315,7 @@ asmlinkage int do_IRQ(struct pt_regs *regs, int isfake)
}
ppc_irq_dispatch_handler( regs, irq );
if ( ppc_md.post_irq )
- ppc_md.post_irq( irq );
+ ppc_md.post_irq( regs, irq );
out:
hardirq_exit( cpu );
diff --git a/arch/ppc/kernel/local_irq.h b/arch/ppc/kernel/local_irq.h
index 602192013..840b14d6f 100644
--- a/arch/ppc/kernel/local_irq.h
+++ b/arch/ppc/kernel/local_irq.h
@@ -4,6 +4,8 @@
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
+#include <linux/cache.h>
+#include <linux/spinlock.h>
#include <linux/irq.h>
void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index aa9f5ac83..fde7112c7 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -20,13 +20,13 @@
#include <asm/page.h>
#include "ppc_asm.h"
-#ifndef CONFIG_8xx
-CACHE_LINE_SIZE = 32
-LG_CACHE_LINE_SIZE = 5
-#else
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx)
CACHE_LINE_SIZE = 16
LG_CACHE_LINE_SIZE = 4
-#endif /* CONFIG_8xx */
+#else
+CACHE_LINE_SIZE = 32
+LG_CACHE_LINE_SIZE = 5
+#endif /* CONFIG_4xx || CONFIG_8xx */
.text
@@ -590,6 +590,20 @@ _GLOBAL(_set_THRM3)
_GLOBAL(_get_PVR)
mfspr r3,PVR
blr
+
+_GLOBAL(_get_HID0)
+ mfspr r3,HID0
+ blr
+
+_GLOBAL(_get_ICTC)
+ mfspr r3,ICTC
+ blr
+
+_GLOBAL(_set_ICTC)
+ mtspr ICTC,r3
+ blr
+
+
/*
L2CR functions
Copyright © 1997-1998 by PowerLogix R & D, Inc.
@@ -656,6 +670,8 @@ _GLOBAL(_set_L2CR)
rlwinm r4,r4,16,16,31
cmplwi r4,0x0008
beq thisIs750
+ cmplwi r4,0x000c
+ beq thisIs750
li r3,-1
blr
@@ -750,9 +766,11 @@ _GLOBAL(_get_L2CR)
mfspr r3,PVR
rlwinm r3,r3,16,16,31
cmplwi r3,0x0008
+ beq 1f
+ cmplwi r3,0x000c
li r3,0
bnelr
-
+1:
/* Return the L2CR contents */
mfspr r3,L2CR
blr
diff --git a/arch/ppc/kernel/oak_setup.c b/arch/ppc/kernel/oak_setup.c
index ad2c224bb..f3c142e2b 100644
--- a/arch/ppc/kernel/oak_setup.c
+++ b/arch/ppc/kernel/oak_setup.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
*
* Module name: oak_setup.c
*
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/param.h>
#include <linux/string.h>
+#include <linux/blk.h>
#include <asm/processor.h>
#include <asm/board.h>
@@ -30,6 +31,12 @@
#include "time.h"
#include "oak_setup.h"
+
+
+
+
+
+
/* Function Prototypes */
extern void abort(void);
@@ -95,32 +102,32 @@ oak_init(unsigned long r3, unsigned long r4, unsigned long r5,
/* Initialize machine-dependency vectors */
- ppc_md.setup_arch = oak_setup_arch;
- ppc_md.setup_residual = oak_setup_residual;
- ppc_md.get_cpuinfo = NULL;
- ppc_md.irq_cannonicalize = NULL;
- ppc_md.init_IRQ = oak_init_IRQ;
- ppc_md.get_irq = oak_get_irq;
- ppc_md.init = NULL;
-
- ppc_md.restart = oak_restart;
- ppc_md.power_off = oak_power_off;
- ppc_md.halt = oak_halt;
-
- ppc_md.time_init = oak_time_init;
- ppc_md.set_rtc_time = oak_set_rtc_time;
- ppc_md.get_rtc_time = oak_get_rtc_time;
- ppc_md.calibrate_decr = oak_calibrate_decr;
-
- ppc_md.kbd_setkeycode = NULL;
- ppc_md.kbd_getkeycode = NULL;
- ppc_md.kbd_translate = NULL;
- ppc_md.kbd_unexpected_up = NULL;
- ppc_md.kbd_leds = NULL;
- ppc_md.kbd_init_hw = NULL;
+ ppc_md.setup_arch = oak_setup_arch;
+ ppc_md.setup_residual = oak_setup_residual;
+ ppc_md.get_cpuinfo = NULL;
+ ppc_md.irq_cannonicalize = NULL;
+ ppc_md.init_IRQ = oak_init_IRQ;
+ ppc_md.get_irq = oak_get_irq;
+ ppc_md.init = NULL;
+
+ ppc_md.restart = oak_restart;
+ ppc_md.power_off = oak_power_off;
+ ppc_md.halt = oak_halt;
+
+ ppc_md.time_init = oak_time_init;
+ ppc_md.set_rtc_time = oak_set_rtc_time;
+ ppc_md.get_rtc_time = oak_get_rtc_time;
+ ppc_md.calibrate_decr = oak_calibrate_decr;
+
+ ppc_md.kbd_setkeycode = NULL;
+ ppc_md.kbd_getkeycode = NULL;
+ ppc_md.kbd_translate = NULL;
+ ppc_md.kbd_unexpected_up = NULL;
+ ppc_md.kbd_leds = NULL;
+ ppc_md.kbd_init_hw = NULL;
#if defined(CONFIG_MAGIC_SYSRQ)
- ppc_md.kbd_sysrq_xlate = NULL;
+ ppc_md.ppc_kbd_sysrq_xlate = NULL;
#endif
return;
diff --git a/arch/ppc/kernel/oak_setup.h b/arch/ppc/kernel/oak_setup.h
index 62cfac906..8648bd084 100644
--- a/arch/ppc/kernel/oak_setup.h
+++ b/arch/ppc/kernel/oak_setup.h
@@ -1,14 +1,14 @@
/*
*
- * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
*
- * Module name: oak_setup.c
+ * Module name: oak_setup.h
*
* Description:
* Architecture- / platform-specific boot-time initialization code for
* the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
* code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- * <dmalek@jlc.net>.
+ * <dan@netx4.com>.
*
*/
diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
index 6857aa36f..d4dbe05e5 100644
--- a/arch/ppc/kernel/open_pic.c
+++ b/arch/ppc/kernel/open_pic.c
@@ -8,6 +8,7 @@
* for more details.
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -17,17 +18,30 @@
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/prom.h>
#include "local_irq.h"
volatile struct OpenPIC *OpenPIC = NULL;
u_int OpenPIC_NumInitSenses __initdata = 0;
u_char *OpenPIC_InitSenses __initdata = NULL;
+int open_pic_irq_offset;
+extern int use_of_interrupt_tree;
void chrp_mask_irq(unsigned int);
void chrp_unmask_irq(unsigned int);
+void find_ISUs(void);
static u_int NumProcessors;
static u_int NumSources;
+OpenPIC_Source *ISU;
+/*
+ * We should use this if we have > 1 ISU.
+ * We can just point each entry to the
+ * appropriate source regs but it wastes a lot of space
+ * so until we have >1 ISU I'll leave it unimplemented.
+ * -- Cort
+OpenPIC_Source ISU[128];
+*/
struct hw_interrupt_type open_pic = {
" OpenPIC ",
@@ -38,7 +52,6 @@ struct hw_interrupt_type open_pic = {
0,
0
};
-int open_pic_irq_offset;
/*
* Accesses to the current processor's registers
@@ -96,7 +109,7 @@ void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
#endif /* __SMP__ */
#ifdef __i386__
-static inline u_int ld_le32(volatile u_int *addr)
+static inline u_int in_le32(volatile u_int *addr)
{
return *addr;
}
@@ -111,7 +124,7 @@ u_int openpic_read(volatile u_int *addr)
{
u_int val;
- val = ld_le32(addr);
+ val = in_le32(addr);
return val;
}
@@ -148,6 +161,9 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
{
openpic_setfield(addr, OPENPIC_MASK);
/* wait until it's not in use */
+ /* BenH: Is this code really enough ? I would rather check the result
+ * and eventually retry ...
+ */
while (openpic_read(addr) & OPENPIC_ACTIVITY);
openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
}
@@ -182,16 +198,18 @@ void __init openpic_init(int main_pic)
OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
-
- printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
- NumProcessors, NumSources, OpenPIC);
- timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
- printk("OpenPIC timer frequency is ");
- if (timerfreq)
- printk("%d Hz\n", timerfreq);
- else
- printk("not set\n");
-
+ if ( _machine != _MACH_Pmac )
+ {
+ printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
+ NumProcessors, NumSources, OpenPIC);
+ timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
+ printk("OpenPIC timer frequency is ");
+ if (timerfreq)
+ printk("%d MHz\n", timerfreq>>20);
+ else
+ printk("not set\n");
+ }
+
if ( main_pic )
{
/* Initialize timer interrupts */
@@ -209,24 +227,59 @@ void __init openpic_init(int main_pic)
/* Disabled, Priority 8 */
openpic_initipi(i, 8, OPENPIC_VEC_IPI+i);
}
-
- /* Initialize external interrupts */
- if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc);
- /* SIOint (8259 cascade) is special */
- openpic_initirq(0, 8, open_pic_irq_offset, 1, 1);
- openpic_mapirq(0, 1<<0);
- for (i = 1; i < NumSources; i++) {
- /* Enabled, Priority 8 */
- openpic_initirq(i, 8, open_pic_irq_offset+i, 0,
- i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
- /* Processor 0 */
- openpic_mapirq(i, 1<<0);
+ find_ISUs();
+ if ( _machine != _MACH_Pmac )
+ {
+ /* Initialize external interrupts */
+ if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc);
+ /* SIOint (8259 cascade) is special */
+ openpic_initirq(0, 8, open_pic_irq_offset, 1, 1);
+ openpic_mapirq(0, 1<<0);
+ for (i = 1; i < NumSources; i++) {
+ /* Enabled, Priority 8 */
+ openpic_initirq(i, 8, open_pic_irq_offset+i, 0,
+ i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
+ /* Processor 0 */
+ openpic_mapirq(i, 1<<0);
+ }
}
-
+ else
+ {
+ /* Prevent any interrupt from occuring during initialisation.
+ * Hum... I believe this is not necessary, Apple does that in
+ * Darwin's PowerExpress code.
+ */
+ openpic_set_priority(0, 0xf);
+
+ /* First disable all interrupts and map them to CPU 0 */
+ for (i = 0; i < NumSources; i++) {
+ openpic_disable_irq(i);
+ openpic_mapirq(i, 1<<0);
+ }
+
+ /* If we use the device tree, then lookup all interrupts and
+ * initialize them according to sense infos found in the tree
+ */
+ if (use_of_interrupt_tree) {
+ struct device_node* np = find_all_nodes();
+ while(np) {
+ int j, pri;
+ pri = strcmp(np->name, "programmer-switch") ? 2 : 7;
+ for (j=0;j<np->n_intrs;j++)
+ openpic_initirq( np->intrs[j].line,
+ pri,
+ np->intrs[j].line,
+ np->intrs[j].sense,
+ np->intrs[j].sense);
+ np = np->next;
+ }
+ }
+ }
+
/* Initialize the spurious interrupt */
if ( ppc_md.progress ) ppc_md.progress("openpic spurious",0x3bd);
openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
- if ( _machine != _MACH_gemini )
+ if ( !(_machine && (_MACH_gemini|_MACH_Pmac)) )
{
if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
"82c59 cascade", NULL))
@@ -238,6 +291,20 @@ void __init openpic_init(int main_pic)
if ( ppc_md.progress ) ppc_md.progress("openpic exit",0x222);
}
+void find_ISUs(void)
+{
+#ifdef CONFIG_PPC64
+ /* hardcode this for now since the IBM 260 is the only thing with
+ * a distributed openpic right now. -- Cort
+ */
+ ISU = (OpenPIC_Source *)0xfeff7c00;
+ NumSources = 0x10;
+#else
+ /* for non-distributed OpenPIC implementations it's in the IDU -- Cort */
+ ISU = OpenPIC->Source;
+#endif
+}
+
void openpic_reset(void)
{
openpic_setfield(&OpenPIC->Global.Global_Configuration0,
@@ -279,6 +346,8 @@ void openpic_eoi(u_int cpu)
{
check_arg_cpu(cpu);
openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
+ /* Handle PCI write posting */
+ (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
}
@@ -379,7 +448,7 @@ void do_openpic_setup_cpu(void)
#if 0
/* let the openpic know we want intrs */
for ( i = 0; i < NumSources ; i++ )
- openpic_mapirq(i, openpic_read(&OpenPIC->Source[i].Destination)
+ openpic_mapirq(i, openpic_read(ISU[i].Destination)
| (1<<smp_processor_id()) );
#endif
openpic_set_priority(smp_processor_id(), 0);
@@ -417,13 +486,23 @@ void openpic_maptimer(u_int timer, u_int cpumask)
void openpic_enable_irq(u_int irq)
{
check_arg_irq(irq);
- openpic_clearfield(&OpenPIC->Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK);
+ openpic_clearfield(&ISU[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK);
+ /* make sure mask gets to controller before we return to user */
+ do {
+ mb(); /* sync is probably useless here */
+ } while(openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_MASK));
}
void openpic_disable_irq(u_int irq)
{
check_arg_irq(irq);
- openpic_setfield(&OpenPIC->Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK);
+ openpic_setfield(&ISU[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK);
+ /* make sure mask gets to controller before we return to user */
+ do {
+ mb(); /* sync is probably useless here */
+ } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_MASK));
}
/*
@@ -440,12 +519,13 @@ void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
check_arg_irq(irq);
check_arg_pri(pri);
check_arg_vec(vec);
- openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
+ openpic_safe_writefield(&ISU[irq].Vector_Priority,
OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
- OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
+ OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
(pri << OPENPIC_PRIORITY_SHIFT) | vec |
- (pol ? OPENPIC_SENSE_POLARITY : 0) |
- (sense ? OPENPIC_SENSE_LEVEL : 0));
+ (pol ? OPENPIC_POLARITY_POSITIVE :
+ OPENPIC_POLARITY_NEGATIVE) |
+ (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
}
/*
@@ -454,7 +534,7 @@ void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
void openpic_mapirq(u_int irq, u_int cpumask)
{
check_arg_irq(irq);
- openpic_write(&OpenPIC->Source[irq].Destination, cpumask);
+ openpic_write(&ISU[irq].Destination, cpumask);
}
/*
@@ -465,7 +545,7 @@ void openpic_mapirq(u_int irq, u_int cpumask)
void openpic_set_sense(u_int irq, int sense)
{
check_arg_irq(irq);
- openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
+ openpic_safe_writefield(&ISU[irq].Vector_Priority,
OPENPIC_SENSE_LEVEL,
(sense ? OPENPIC_SENSE_LEVEL : 0));
}
diff --git a/arch/ppc/kernel/pci-dma.c b/arch/ppc/kernel/pci-dma.c
new file mode 100644
index 000000000..089566908
--- /dev/null
+++ b/arch/ppc/kernel/pci-dma.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com>
+ *
+ *
+ * Dynamic DMA mapping support.
+ *
+ * swiped from i386
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/* Pure 2^n version of get_order */
+extern __inline__ int __get_order(unsigned long size)
+{
+ int order;
+
+ size = (size-1) >> (PAGE_SHIFT-1);
+ order = -1;
+ do {
+ size >>= 1;
+ order++;
+ } while (size);
+ return order;
+}
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+ dma_addr_t *dma_handle)
+{
+ void *ret;
+ int gfp = GFP_ATOMIC;
+
+ if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+ gfp |= GFP_DMA;
+ ret = (void *)__get_free_pages(gfp, __get_order(size));
+
+ if (ret != NULL) {
+ memset(ret, 0, size);
+ *dma_handle = virt_to_bus(ret);
+ }
+ return ret;
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ free_pages((unsigned long)vaddr, __get_order(size));
+}
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 6c98bbf2c..8326bc369 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -71,9 +71,9 @@ void __init pcibios_init(void)
{
printk("PCI: Probing PCI hardware\n");
pci_scan_bus(0, &generic_pci_ops, NULL);
- pcibios_claim_resources(&pci_root_buses);
if (ppc_md.pcibios_fixup)
ppc_md.pcibios_fixup();
+ pcibios_claim_resources(&pci_root_buses);
}
void __init
diff --git a/arch/ppc/kernel/pmac_nvram.c b/arch/ppc/kernel/pmac_nvram.c
index ea3338aef..a3a9bae70 100644
--- a/arch/ppc/kernel/pmac_nvram.c
+++ b/arch/ppc/kernel/pmac_nvram.c
@@ -6,6 +6,7 @@
#include <linux/stddef.h>
#include <linux/nvram.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <asm/init.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -20,23 +21,37 @@
static int nvram_naddrs;
static volatile unsigned char *nvram_addr;
static volatile unsigned char *nvram_data;
-static int nvram_mult;
-
-#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
-
+static int nvram_mult, is_core_99;
+static char* nvram_image;
+
+#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
+
__init
void pmac_nvram_init(void)
{
struct device_node *dp;
+ nvram_naddrs = 0;
+
dp = find_devices("nvram");
if (dp == NULL) {
printk(KERN_ERR "Can't find NVRAM device\n");
- nvram_naddrs = 0;
return;
}
nvram_naddrs = dp->n_addrs;
- if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+ is_core_99 = device_is_compatible(dp, "nvram,flash");
+ if (is_core_99)
+ {
+ int i;
+ if (nvram_naddrs < 1)
+ return;
+ nvram_image = kmalloc(dp->addrs[0].size, GFP_KERNEL);
+ if (!nvram_image)
+ return;
+ nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ for (i=0; i<dp->addrs[0].size; i++)
+ nvram_image[i] = in_8(nvram_data + i);
+ } else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
nvram_mult = 1;
} else if (nvram_naddrs == 1) {
@@ -69,6 +84,8 @@ unsigned char nvram_read_byte(int addr)
return req.reply[1];
#endif
case 1:
+ if (is_core_99)
+ return nvram_image[addr];
return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
case 2:
*nvram_addr = addr >> 5;
@@ -94,6 +111,10 @@ void nvram_write_byte(unsigned char val, int addr)
break;
#endif
case 1:
+ if (is_core_99) {
+ nvram_image[addr] = val;
+ break;
+ }
nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
break;
case 2:
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
index 75f8097fd..b57d5aa28 100644
--- a/arch/ppc/kernel/pmac_pci.c
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -30,6 +30,16 @@
struct bridge_data **bridges, *bridge_list;
static int max_bus;
+struct uninorth_data {
+ struct device_node* node;
+ volatile unsigned int* cfg_addr;
+ volatile unsigned int* cfg_data;
+};
+
+static struct uninorth_data uninorth_bridges[3];
+static int uninorth_count;
+static int uninorth_default = -1;
+
static void add_bridges(struct device_node *dev);
/*
@@ -73,6 +83,159 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
return 0;
}
+/* This function only works for bus 0, uni-N uses a different mecanism for
+ * other busses (see below)
+ */
+#define UNI_N_CFA0(devfn, off) \
+ ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+ | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+ | (((unsigned long)(off)) & 0xFCUL))
+
+/* This one is for type 1 config accesses */
+#define UNI_N_CFA1(bus, devfn, off) \
+ ((((unsigned long)(bus)) << 16) \
+ |(((unsigned long)(devfn)) << 8) \
+ |(((unsigned long)(off)) & 0xFCUL) \
+ |1UL)
+
+/* We should really use RTAS here, unfortunately, it's not available with BootX.
+ * (one more reason for writing a beautiful OF booter). I'll do the RTAS stuff
+ * later, once I have something that works enough with BootX.
+ */
+__pmac static
+unsigned int
+uni_north_access_data(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset)
+{
+ struct device_node *node, *bridge_node;
+ int bridge = uninorth_default;
+ unsigned int caddr;
+
+ if (bus == 0) {
+ if (PCI_SLOT(dev_fn) < 11) {
+ return 0;
+ }
+ /* We look for the OF device corresponding to this bus/devfn pair. If we
+ * don't find it, we default to the external PCI */
+ bridge_node = NULL;
+ node = find_pci_device_OFnode(bus, dev_fn & 0xf8);
+ if (node) {
+ /* note: we don't stop on the first occurence since we need to go
+ * up to the root bridge */
+ do {
+ if (!strcmp(node->type, "pci"))
+ bridge_node = node;
+ node=node->parent;
+ } while (node);
+ }
+ if (bridge_node) {
+ int i;
+ for (i=0;i<uninorth_count;i++)
+ if (uninorth_bridges[i].node == bridge_node) {
+ bridge = i;
+ break;
+ }
+ }
+ caddr = UNI_N_CFA0(dev_fn, offset);
+ } else
+ caddr = UNI_N_CFA1(bus, dev_fn, offset);
+
+ if (bridge == -1) {
+ printk(KERN_WARNING "pmac_pci: no default bridge !\n");
+ return 0;
+ }
+
+ /* Uninorth will return garbage if we don't read back the value ! */
+ out_le32(uninorth_bridges[bridge].cfg_addr, caddr);
+ (void)in_le32(uninorth_bridges[bridge].cfg_addr);
+ /* Yes, offset is & 7, not & 3 ! */
+ return (unsigned int)(uninorth_bridges[bridge].cfg_data) + (offset & 0x07);
+}
+
+__pmac
+int uni_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ unsigned int addr;
+
+ *val = 0xff;
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ *val = in_8((volatile unsigned char*)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ unsigned int addr;
+
+ *val = 0xffff;
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ *val = in_le16((volatile unsigned short*)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ unsigned int addr;
+
+ *val = 0xffff;
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ *val = in_le32((volatile unsigned int*)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ unsigned int addr;
+
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_8((volatile unsigned char *)addr, val);
+ (void)in_8((volatile unsigned char *)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ unsigned int addr;
+
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le16((volatile unsigned short *)addr, val);
+ (void)in_le16((volatile unsigned short *)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ unsigned int addr;
+
+ addr = uni_north_access_data(bus, dev_fn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32((volatile unsigned int *)addr, val);
+ (void)in_le32((volatile unsigned int *)addr);
+ return PCIBIOS_SUCCESSFUL;
+}
+
__pmac
int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val)
@@ -362,6 +525,21 @@ static void __init init_bandit(struct bridge_data *bp)
bp->io_base);
}
+#define GRACKLE_STG_ENABLE 0x00000040
+
+/* N.B. this is called before bridges is initialized, so we can't
+ use grackle_pcibios_{read,write}_config_dword. */
+static inline void grackle_set_stg(struct bridge_data *bp, int enable)
+{
+ unsigned int val;
+
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ val = in_le32((volatile unsigned int *)bp->cfg_data);
+ val = enable? (val | GRACKLE_STG_ENABLE): (val & ~GRACKLE_STG_ENABLE);
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ out_le32((volatile unsigned int *)bp->cfg_data, val);
+}
+
void __init pmac_find_bridges(void)
{
int bus;
@@ -411,20 +589,47 @@ static void __init add_bridges(struct device_node *dev)
printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
bus_range[1]);
printk(" controlled by %s at %x\n", dev->name, addr->address);
+ if (device_is_compatible(dev, "uni-north")) {
+ int i = uninorth_count++;
+ uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+ uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+ uninorth_bridges[i].node = dev;
+ /* XXX This is the bridge with the PCI expansion bus. This is also the
+ * address of the bus that will receive type 1 config accesses and io
+ * accesses. Appears to be correct for iMac DV and G4 Sawtooth too.
+ * That means that we cannot do io cycles on the AGP bus nor the internal
+ * ethernet/fw bus. Fortunately, they appear not to be needed on iMac DV
+ * and G4 neither.
+ */
+ if (addr->address == 0xf2000000)
+ uninorth_default = i;
+ else
+ continue;
+ }
+
bp = (struct bridge_data *) alloc_bootmem(sizeof(*bp));
- if (strcmp(dev->name, "pci") != 0) {
- bp->cfg_addr = (volatile unsigned int *)
- ioremap(addr->address + 0x800000, 0x1000);
- bp->cfg_data = (volatile unsigned char *)
- ioremap(addr->address + 0xc00000, 0x1000);
- bp->io_base = (void *) ioremap(addr->address, 0x10000);
- } else {
- /* XXX */
+ if (device_is_compatible(dev, "uni-north")) {
+ bp->cfg_addr = 0;
+ bp->cfg_data = 0;
+ /* is 0x10000 enough for io space ? */
+ bp->io_base = (void *)ioremap(addr->address, 0x10000);
+ } else if (strcmp(dev->name, "pci") == 0) {
+ /* XXX assume this is a mpc106 (grackle) */
bp->cfg_addr = (volatile unsigned int *)
ioremap(0xfec00000, 0x1000);
bp->cfg_data = (volatile unsigned char *)
ioremap(0xfee00000, 0x1000);
bp->io_base = (void *) ioremap(0xfe000000, 0x20000);
+#if 0 /* Disabled for now, HW problems */
+ grackle_set_stg(bp, 1);
+#endif
+ } else {
+ /* a `bandit' or `chaos' bridge */
+ bp->cfg_addr = (volatile unsigned int *)
+ ioremap(addr->address + 0x800000, 0x1000);
+ bp->cfg_data = (volatile unsigned char *)
+ ioremap(addr->address + 0xc00000, 0x1000);
+ bp->io_base = (void *) ioremap(addr->address, 0x10000);
}
if (isa_io_base == 0)
isa_io_base = (unsigned long) bp->io_base;
@@ -453,7 +658,7 @@ fix_intr(struct device_node *node, struct pci_dev *dev)
for (; node != 0;node = node->sibling) {
class_code = (unsigned int *) get_property(node, "class-code", 0);
- if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
+ if(class_code && (*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
fix_intr(node->child, dev);
reg = (unsigned int *) get_property(node, "reg", 0);
if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
@@ -490,20 +695,38 @@ pmac_pcibios_fixup(void)
if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
!pin)
continue; /* No interrupt generated -> no fixup */
- fix_intr(bp->node->child, dev);
+ /* We iterate all instances of uninorth for now */
+ if (uninorth_count && dev->bus->number == 0) {
+ int i;
+ for (i=0;i<uninorth_count;i++)
+ fix_intr(uninorth_bridges[i].node->child, dev);
+ } else
+ fix_intr(bp->node->child, dev);
}
}
void __init
pmac_setup_pci_ptrs(void)
{
- if (find_devices("pci") != 0) {
- /* looks like a G3 powermac */
- set_config_access_method(grackle);
- } else {
+ struct device_node* np;
+
+ np = find_devices("pci");
+ if (np != 0)
+ {
+ if (device_is_compatible(np, "uni-north"))
+ {
+ /* looks like an Core99 powermac */
+ set_config_access_method(uni);
+ } else
+ {
+ /* looks like a G3 powermac */
+ set_config_access_method(grackle);
+ }
+ } else
+ {
set_config_access_method(pmac);
}
-
+
ppc_md.pcibios_fixup = pmac_pcibios_fixup;
}
diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c
index 385e23327..d2d5e6b25 100644
--- a/arch/ppc/kernel/pmac_pic.c
+++ b/arch/ppc/kernel/pmac_pic.c
@@ -3,6 +3,8 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/signal.h>
+#include <linux/pci.h>
+#include <linux/openpic.h>
#include <asm/init.h>
#include <asm/io.h>
@@ -27,12 +29,38 @@ static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
static int max_irqs;
static int max_real_irqs;
+static int has_openpic = 0;
#define MAXCOUNT 10000000
#define GATWICK_IRQ_POOL_SIZE 10
static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
+extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+
+static void pmac_openpic_mask_irq(unsigned int irq_nr)
+{
+ openpic_disable_irq(irq_nr);
+}
+
+static void pmac_openpic_unmask_irq(unsigned int irq_nr)
+{
+ openpic_enable_irq(irq_nr);
+}
+
+struct hw_interrupt_type pmac_open_pic = {
+ " OpenPIC ",
+ NULL,
+ NULL,
+ pmac_openpic_unmask_irq,
+ pmac_openpic_mask_irq,
+ pmac_openpic_mask_irq,
+ 0
+};
+
static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr)
{
unsigned long bit = 1UL << (irq_nr & 0x1f);
@@ -141,74 +169,6 @@ static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
ppc_irq_dispatch_handler( regs, irq );
}
-#if 0
-void
-pmac_do_IRQ(struct pt_regs *regs,
- int cpu,
- int isfake)
-{
- int irq;
- unsigned long bits = 0;
-
-#ifdef __SMP__
- /* IPI's are a hack on the powersurge -- Cort */
- if ( cpu != 0 )
- {
-#ifdef CONFIG_XMON
- static int xmon_2nd;
- if (xmon_2nd)
- xmon(regs);
-#endif
- pmac_smp_message_recv();
- return -1;
- }
-
- {
- unsigned int loops = MAXCOUNT;
- while (test_bit(0, &global_irq_lock)) {
- if (smp_processor_id() == global_irq_holder) {
- printk("uh oh, interrupt while we hold global irq lock!\n");
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- break;
- }
- if (loops-- == 0) {
- printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- }
- }
- }
-#endif /* __SMP__ */
-
- for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
- int i = irq >> 5;
- bits = ld_le32(&pmac_irq_hw[i]->flag)
- | ppc_lost_interrupts[i];
- if (bits == 0)
- continue;
- irq -= cntlzw(bits);
- break;
- }
-
- if (irq < 0)
- {
- printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
- irq, regs->nip);
- ppc_spurious_interrupts++;
- }
- else
- {
- ppc_irq_dispatch_handler( regs, irq );
- }
-#ifdef CONFIG_SMP
-out:
-#endif /* CONFIG_SMP */
-}
-#endif
-
int
pmac_get_irq(struct pt_regs *regs)
{
@@ -248,15 +208,30 @@ pmac_get_irq(struct pt_regs *regs)
}
#endif /* __SMP__ */
- for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
- int i = irq >> 5;
- bits = ld_le32(&pmac_irq_hw[i]->flag)
- | ppc_lost_interrupts[i];
- if (bits == 0)
- continue;
- irq -= cntlzw(bits);
- break;
- }
+ /* Yeah, I know, this could be a separate do_IRQ function */
+ if (has_openpic)
+ {
+ irq = openpic_irq(smp_processor_id());
+ if (irq == OPENPIC_VEC_SPURIOUS)
+ /* We get those when doing polled ADB requests,
+ * using -2 is a temp hack to disable the printk
+ */
+ irq = -2; /*-1; */
+ else
+ openpic_eoi(smp_processor_id());
+ }
+ else
+ {
+ for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
+ int i = irq >> 5;
+ bits = ld_le32(&pmac_irq_hw[i]->flag)
+ | ppc_lost_interrupts[i];
+ if (bits == 0)
+ continue;
+ irq -= cntlzw(bits);
+ break;
+ }
+ }
return irq;
}
@@ -339,6 +314,51 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
}
}
+/*
+ * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
+ * card which includes an ohare chip that acts as a second interrupt
+ * controller. If we find this second ohare, set it up and fix the
+ * interrupt value in the device tree for the ethernet chip.
+ */
+static void __init enable_second_ohare(void)
+{
+ unsigned char bus, devfn;
+ unsigned short cmd;
+ unsigned long addr;
+ int second_irq;
+ struct device_node *irqctrler = find_devices("pci106b,7");
+ struct device_node *ether;
+
+ if (irqctrler == NULL || irqctrler->n_addrs <= 0)
+ return;
+ addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
+ pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
+ max_irqs = 64;
+ if (pci_device_loc(irqctrler, &bus, &devfn) == 0) {
+ pmac_pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ cmd &= ~PCI_COMMAND_IO;
+ pmac_pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+ }
+
+ second_irq = irqctrler->intrs[0].line;
+ printk(KERN_INFO "irq: secondary controller on irq %d\n", second_irq);
+ request_irq(second_irq, gatwick_action, SA_INTERRUPT,
+ "interrupt cascade", 0 );
+
+ /* Fix interrupt for the modem/ethernet combo controller. The number
+ in the device tree (27) is bogus (correct for the ethernet-only
+ board but not the combo ethernet/modem board).
+ The real interrupt is 28 on the second controller -> 28+32 = 60.
+ */
+ ether = find_devices("pci1011,14");
+ if (ether && ether->n_intrs > 0) {
+ ether->intrs[0].line = 60;
+ printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
+ ether->intrs[0].line);
+ }
+}
+
void __init
pmac_pic_init(void)
{
@@ -347,9 +367,44 @@ pmac_pic_init(void)
unsigned long addr;
int second_irq = -999;
+ /* We first try to detect Apple's new Core99 chipset, since mac-io
+ * is quite different on those machines and contains an IBM MPIC2.
+ */
+ irqctrler = find_type_devices("open-pic");
+ if (irqctrler != NULL)
+ {
+ printk("PowerMac using OpenPIC irq controller\n");
+ if (irqctrler->n_addrs > 0)
+ {
+#ifdef CONFIG_XMON
+ struct device_node* pswitch;
+#endif /* CONFIG_XMON */
+ OpenPIC = (volatile struct OpenPIC *)
+ ioremap(irqctrler->addrs[0].address,
+ irqctrler->addrs[0].size);
+ for ( i = 0 ; i < NR_IRQS ; i++ )
+ irq_desc[i].handler = &pmac_open_pic;
+ openpic_init(1);
+ has_openpic = 1;
+#ifdef CONFIG_XMON
+ pswitch = find_devices("programmer-switch");
+ if (pswitch && pswitch->n_intrs)
+ request_irq(pswitch->intrs[0].line, xmon_irq, 0,
+ "NMI - XMON", 0);
+#endif /* CONFIG_XMON */
+ return;
+ }
+ irqctrler = NULL;
+ }
- /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128,
- others have 32 */
+ /*
+ * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
+ * 1998 G3 Series PowerBooks have 128,
+ * other powermacs have 32.
+ * The combo ethernet/modem card for the Powerstar powerbooks
+ * (2400/3400/3500, ohare based) has a second ohare chip
+ * effectively making a total of 64.
+ */
max_irqs = max_real_irqs = 32;
irqctrler = find_devices("mac-io");
if (irqctrler)
@@ -389,6 +444,12 @@ pmac_pic_init(void)
pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
}
+ /* PowerBooks 3400 and 3500 can have a second controller in a second
+ ohare chip, on the combo ethernet/modem card */
+ if (machine_is_compatible("AAPL,3400/2400")
+ || machine_is_compatible("AAPL,3500"))
+ enable_second_ohare();
+
/* disable all interrupts in all controllers */
for (i = 0; i * 32 < max_irqs; ++i)
out_le32(&pmac_irq_hw[i]->enable, 0);
@@ -435,7 +496,12 @@ sleep_save_intrs(int viaint)
out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
if (max_real_irqs > 32)
out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
- mb();
+ (void)in_le32(&pmac_irq_hw[0]->flag);
+ do {
+ /* make sure mask gets to controller before we
+ return to user */
+ mb();
+ } while(in_le32(&pmac_irq_hw[0]->enable) != ppc_cached_irq_mask[0]);
}
void
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
index 72d23a934..e1c1815ac 100644
--- a/arch/ppc/kernel/pmac_setup.c
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -104,6 +104,10 @@ extern char saved_command_line[];
extern void zs_kgdb_hook(int tty_num);
static void ohare_init(void);
static void init_p2pbridge(void);
+static void init_uninorth(void);
+#ifdef CONFIG_BOOTX_TEXT
+void pmac_progress(char *s, unsigned short hex);
+#endif
__pmac
int
@@ -232,8 +236,10 @@ pmac_setup_arch(void)
if (fp != 0) {
switch (_get_PVR() >> 16) {
case 4: /* 604 */
+ case 8: /* G3 */
case 9: /* 604e */
case 10: /* mach V (604ev5) */
+ case 12: /* G4 */
case 20: /* 620 */
loops_per_sec = *fp;
break;
@@ -252,9 +258,10 @@ pmac_setup_arch(void)
pmac_find_bridges();
init_p2pbridge();
-
+ init_uninorth();
+
/* Checks "l2cr-value" property in the registry */
- if ( (_get_PVR() >> 16) == 8) {
+ if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) {
struct device_node *np = find_devices("cpus");
if (np == 0)
np = find_type_devices("cpu");
@@ -346,6 +353,33 @@ static void __init ohare_init(void)
}
}
+static void __init
+init_uninorth(void)
+{
+ /*
+ * Turns on the gmac clock so that it responds to PCI cycles
+ * later, the driver may want to turn it off again to save
+ * power when interface is down
+ */
+ struct device_node* uni_n = find_devices("uni-n");
+ struct device_node* gmac = find_devices("ethernet");
+ unsigned long* addr;
+
+ if (!uni_n || uni_n->n_addrs < 1)
+ return;
+ addr = ioremap(uni_n->addrs[0].address, 0x300);
+
+ while(gmac) {
+ if (device_is_compatible(gmac, "gmac"))
+ break;
+ gmac = gmac->next;
+ }
+ if (gmac) {
+ *(addr + 8) |= 2;
+ eieio();
+ }
+}
+
extern char *bootpath;
extern char *bootdevice;
void *boot_host;
@@ -401,14 +435,11 @@ note_scsi_host(struct device_node *node, void *host)
#endif
#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-extern int pmac_ide_count;
-extern struct device_node *pmac_ide_node[];
-static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89, 90, 91 };
kdev_t __init find_ide_boot(void)
{
char *p;
- int i, n;
+ int n;
if (bootdevice == NULL)
return 0;
@@ -417,18 +448,7 @@ kdev_t __init find_ide_boot(void)
return 0;
n = p - bootdevice;
- /*
- * Look through the list of IDE interfaces for this one.
- */
- for (i = 0; i < pmac_ide_count; ++i) {
- char *name = pmac_ide_node[i]->full_name;
- if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
- /* XXX should cope with the 2nd drive as well... */
- return MKDEV(ide_majors[i], 0);
- }
- }
-
- return 0;
+ return pmac_find_ide_boot(bootdevice, n);
}
#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
@@ -464,10 +484,10 @@ void note_bootable_part(kdev_t dev, int part)
find_boot_device();
found_boot = 1;
}
- if (dev == boot_dev) {
+ if (boot_dev == 0 || dev == boot_dev) {
ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
boot_dev = NODEV;
- printk(" (root)");
+ printk(" (root on %d)", part);
}
}
@@ -550,11 +570,15 @@ pmac_ide_default_irq(ide_ioreg_t base)
return 0;
}
+#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
+extern ide_ioreg_t pmac_ide_get_base(int index);
+#endif
+
ide_ioreg_t
pmac_ide_default_io_base(int index)
{
#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
- return pmac_ide_regbase[index];
+ return pmac_ide_get_base(index);
#else
return 0;
#endif
@@ -660,5 +684,22 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
ppc_ide_md.io_base = _IO_BASE; /* actually too early for this :-( */
-#endif
+#endif
+#ifdef CONFIG_BOOTX_TEXT
+ ppc_md.progress = pmac_progress;
+#endif
+ if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
+
}
+
+#ifdef CONFIG_BOOTX_TEXT
+extern void drawchar(char c);
+extern void drawstring(const char *c);
+void
+pmac_progress(char *s, unsigned short hex)
+{
+ drawstring(s);
+ drawchar('\n');
+}
+#endif CONFIG_BOOTX_TEXT
+
diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c
index 3b7dd283f..1c935a625 100644
--- a/arch/ppc/kernel/pmac_time.c
+++ b/arch/ppc/kernel/pmac_time.c
@@ -71,8 +71,8 @@ unsigned long pmac_get_rtc_time(void)
if (req.reply_len != 7)
printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
req.reply_len);
- return (req.reply[3] << 24) + (req.reply[4] << 16)
- + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+ return (unsigned long)(req.reply[1] << 24) + (req.reply[2] << 16)
+ + (req.reply[3] << 8) + (unsigned long)req.reply[4] - RTC_OFFSET;
#endif /* CONFIG_ADB_CUDA */
#ifdef CONFIG_ADB_PMU
case SYS_CTRLER_PMU:
diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c
index b6397daac..42ca7eadc 100644
--- a/arch/ppc/kernel/ppc-stub.c
+++ b/arch/ppc/kernel/ppc-stub.c
@@ -351,7 +351,7 @@ static inline int get_msr()
static inline void set_msr(int msr)
{
- asm volatile("mfmsr %0" : : "r" (msr));
+ asm volatile("mtmsr %0" : : "r" (msr));
}
/* Set up exception handlers for tracing and breakpoints
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index b90fa7a2c..264a24d48 100644
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -45,17 +45,9 @@ extern unsigned long pte_misses;
extern unsigned long pte_errors;
static struct file_operations ppc_htab_operations = {
- ppc_htab_lseek, /* lseek */
- ppc_htab_read, /* read */
- ppc_htab_write, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
+ llseek: ppc_htab_lseek,
+ read: ppc_htab_read,
+ write: ppc_htab_write,
};
/*
@@ -531,7 +523,8 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
"0.5", "1.0", "(reserved2)", "(reserved3)"
};
- if ( (_get_PVR() >> 16) != 8) return -EFAULT;
+ if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12))
+ return -EFAULT;
if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
*lenp = 0;
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 65e925034..9a5444a51 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -229,6 +229,8 @@ EXPORT_SYMBOL(find_path_device);
EXPORT_SYMBOL(find_phandle);
EXPORT_SYMBOL(device_is_compatible);
EXPORT_SYMBOL(machine_is_compatible);
+EXPORT_SYMBOL(find_pci_device_OFnode);
+EXPORT_SYMBOL(find_all_nodes);
EXPORT_SYMBOL(get_property);
EXPORT_SYMBOL(pci_io_base);
EXPORT_SYMBOL(pci_device_loc);
diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c
index 633757875..fd14fc483 100644
--- a/arch/ppc/kernel/prep_pci.c
+++ b/arch/ppc/kernel/prep_pci.c
@@ -40,7 +40,7 @@ unsigned char *Motherboard_routes;
static unsigned long *ProcInfo;
extern int chrp_get_irq(struct pt_regs *);
-extern void chrp_post_irq(int);
+extern void chrp_post_irq(struct pt_regs* regs, int);
/* Tables for known hardware */
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 241b7c33c..ed98ba6f0 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -57,6 +57,8 @@ union task_union __attribute((aligned(16))) init_task_union = {
};
/* only used to get secondary processor up */
struct task_struct *current_set[NR_CPUS] = {&init_task, };
+char *sysmap = NULL;
+unsigned long sysmap_size = 0;
#undef SHOW_TASK_SWITCHES 1
#undef CHECK_STACK 1
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
index 049cde10f..a52bdd804 100644
--- a/arch/ppc/kernel/prom.c
+++ b/arch/ppc/kernel/prom.c
@@ -30,6 +30,10 @@
#include <asm/system.h>
#include <asm/gemini.h>
+#ifdef CONFIG_FB
+#include <asm/linux_logo.h>
+#endif
+
/*
* Properties whose value is longer than this get excluded from our
* copy of the device tree. This way we don't waste space storing
@@ -91,7 +95,7 @@ unsigned int prom_num_displays = 0;
char *of_stdout_device = 0;
prom_entry prom = 0;
-ihandle prom_chosen = 0, prom_stdout = 0;
+ihandle prom_chosen = 0, prom_stdout = 0, prom_disp_node = 0;
extern char *klimit;
char *bootpath = 0;
@@ -102,33 +106,35 @@ unsigned int rtas_entry = 0; /* physical pointer */
unsigned int rtas_size = 0;
unsigned int old_rtas = 0;
+int use_of_interrupt_tree = 0;
static struct device_node *allnodes = 0;
+#ifdef CONFIG_BOOTX_TEXT
+
static void clearscreen(void);
static void flushscreen(void);
-#ifdef CONFIG_BOOTX_TEXT
-
void drawchar(char c);
void drawstring(const char *c);
static void drawhex(unsigned long v);
static void scrollscreen(void);
static void draw_byte(unsigned char c, long locX, long locY);
-static void draw_byte_32(unsigned char *bits, unsigned long *base);
-static void draw_byte_16(unsigned char *bits, unsigned long *base);
-static void draw_byte_8(unsigned char *bits, unsigned long *base);
+static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);
-static long g_loc_X;
-static long g_loc_Y;
-static long g_max_loc_X;
-static long g_max_loc_Y;
+/* We want those in data, not BSS */
+static long g_loc_X = 0;
+static long g_loc_Y = 0;
+static long g_max_loc_X = 0;
+static long g_max_loc_Y = 0;
#define cmapsz (16*256)
static unsigned char vga_font[cmapsz];
-#endif
+#endif /* CONFIG_BOOTX_TEXT */
static void *call_prom(const char *service, int nargs, int nret, ...);
@@ -138,15 +144,25 @@ static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
unsigned long, struct device_node ***);
static unsigned long finish_node(struct device_node *, unsigned long,
interpret_func *);
+static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
static unsigned long check_display(unsigned long);
static int prom_next_node(phandle *);
static void *early_get_property(unsigned long, unsigned long, char *);
+#ifdef CONFIG_BOOTX_TEXT
+static void setup_disp_fake_bi(ihandle dp);
+static void prom_welcome(boot_infos_t* bi, unsigned long phys);
+#endif
+
extern void enter_rtas(void *);
extern unsigned long reloc_offset(void);
extern char cmd_line[512]; /* XXX */
boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */
+#ifdef CONFIG_BOOTX_TEXT
+boot_infos_t *disp_bi = 0;
+boot_infos_t fake_bi = {0,};
+#endif
unsigned long dev_tree_size;
/*
@@ -240,7 +256,7 @@ prom_print(const char *msg)
if (RELOC(prom_stdout) == 0)
{
#ifdef CONFIG_BOOTX_TEXT
- if (RELOC(boot_infos) != 0)
+ if (RELOC(disp_bi) != 0)
drawstring(msg);
#endif
return;
@@ -261,7 +277,6 @@ prom_print(const char *msg)
}
}
-unsigned long smp_ibm_chrp_hack __initdata = 0;
unsigned long smp_chrp_cpu_nr __initdata = 1;
/*
@@ -269,23 +284,29 @@ unsigned long smp_chrp_cpu_nr __initdata = 1;
* handling exceptions and the MMU hash table for us.
*/
__init
-void
+unsigned long
prom_init(int r3, int r4, prom_entry pp)
{
#ifdef CONFIG_SMP
int i;
phandle node;
char type[16], *path;
-#endif
+#endif
+ int chrp = 0;
unsigned long mem;
- ihandle prom_rtas;
+ ihandle prom_rtas, prom_mmu, prom_op;
unsigned long offset = reloc_offset();
int l;
char *p, *d;
+ int prom_version = 0;
+ unsigned long phys;
+
+ /* Default */
+ phys = offset + KERNELBASE;
/* check if we're apus, return if we are */
if ( r3 == 0x61707573 )
- return;
+ return phys;
/* If we came here from BootX, clear the screen,
* set up some pointers and return. */
@@ -294,22 +315,20 @@ prom_init(int r3, int r4, prom_entry pp)
unsigned long space;
unsigned long ptr, x;
char *model;
-#ifdef CONFIG_BOOTX_TEXT
- unsigned long flags;
-#endif
RELOC(boot_infos) = PTRUNRELOC(bi);
if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
bi->logicalDisplayBase = 0;
- clearscreen();
-
#ifdef CONFIG_BOOTX_TEXT
RELOC(g_loc_X) = 0;
RELOC(g_loc_Y) = 0;
RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
+ RELOC(disp_bi) = PTRUNRELOC(bi);
+ clearscreen();
+
/* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since
there is nothing much we can do with an incompatible version, except display
a message and eventually hang the processor...
@@ -320,23 +339,9 @@ prom_init(int r3, int r4, prom_entry pp)
if (!BOOT_INFO_IS_COMPATIBLE(bi))
prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));
- prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
- prom_print(RELOC("\nstarted at : 0x"));
- drawhex(reloc_offset() + KERNELBASE);
- prom_print(RELOC("\nlinked at : 0x"));
- drawhex(KERNELBASE);
- prom_print(RELOC("\nframe buffer at : 0x"));
- drawhex((unsigned long)bi->dispDeviceBase);
- prom_print(RELOC(" (phys), 0x"));
- drawhex((unsigned long)bi->logicalDisplayBase);
- prom_print(RELOC(" (log)"));
- prom_print(RELOC("\nMSR : 0x"));
- __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory");
- drawhex(flags);
- prom_print(RELOC("\n\n"));
-#endif
- /* Out of the #if/#endif since it flushes the clearscreen too */
+ prom_welcome(bi, phys);
flushscreen();
+#endif /* CONFIG_BOOTX_TEXT */
/* New BootX enters kernel with MMU off, i/os are not allowed
here. This hack will have been done by the boostrap anyway.
@@ -381,12 +386,12 @@ prom_init(int r3, int r4, prom_entry pp)
prom_print(RELOC("booting...\n"));
flushscreen();
#endif
- return;
+ return phys;
}
/* check if we're prep, return if we are */
if ( *(unsigned long *)(0) == 0xdeadc0de )
- return;
+ return phys;
/* First get a handle for the stdout device */
RELOC(prom) = pp;
@@ -407,6 +412,30 @@ prom_init(int r3, int r4, prom_entry pp)
RELOC(of_stdout_device) = PTRUNRELOC(p);
mem += strlen(p) + 1;
+ /* Find the OF version */
+ prom_op = call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom"));
+ prom_version = 0;
+ if (prom_op != (void*)-1) {
+ char model[64];
+ int sz;
+ sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op, RELOC("model"), model, 64);
+ if (sz > 0) {
+ char *c;
+ /* hack to skip the ibm chrp firmware # */
+ if ( strncmp(model,RELOC("IBM"),3) ) {
+ for (c = model; *c; c++)
+ if (*c >= '0' && *c <= '9') {
+ prom_version = *c - '0';
+ break;
+ }
+ }
+ else
+ chrp = 1;
+ }
+ }
+ if (prom_version >= 3)
+ prom_print(RELOC("OF Version 3 detected.\n"));
+
/* Get the boot device and translate it to a full OF pathname. */
p = (char *) mem;
l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
@@ -478,6 +507,42 @@ prom_init(int r3, int r4, prom_entry pp)
prom_print(RELOC(" done\n"));
}
+ /* If we are already running at 0xc0000000, we assume we were loaded by
+ * an OF bootloader which did set a BAT for us. This breaks OF translate
+ * so we force phys to be 0
+ */
+ if (offset == 0)
+ phys = 0;
+ else {
+ if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
+ RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) {
+ prom_print(RELOC(" no MMU found\n"));
+ } else {
+ int nargs;
+ struct prom_args prom_args;
+ nargs = 4;
+ prom_args.service = RELOC("call-method");
+ prom_args.nargs = nargs;
+ prom_args.nret = 4;
+ prom_args.args[0] = RELOC("translate");
+ prom_args.args[1] = prom_mmu;
+ prom_args.args[2] = (void *)(offset + KERNELBASE);
+ prom_args.args[3] = (void *)1;
+ RELOC(prom)(&prom_args);
+
+ /* We assume the phys. address size is 3 cells */
+ if (prom_args.args[nargs] != 0)
+ prom_print(RELOC(" (translate failed) "));
+ else
+ phys = (unsigned long)prom_args.args[nargs+3];
+ }
+ }
+
+#ifdef CONFIG_BOOTX_TEXT
+ if (!chrp && RELOC(prom_disp_node) != 0)
+ setup_disp_fake_bi(RELOC(prom_disp_node));
+#endif
+
#ifdef CONFIG_SMP
/*
* With CHRP SMP we need to use the OF to start the other
@@ -512,7 +577,7 @@ prom_init(int r3, int r4, prom_entry pp)
node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
if ( (int)call_prom(RELOC("getprop"), 4, 1, node,
RELOC("device_type"),type, sizeof(type)) <= 0)
- return;
+ return phys;
/* copy the holding pattern code to someplace safe (8M) */
memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x100 );
@@ -554,6 +619,79 @@ prom_init(int r3, int r4, prom_entry pp)
prom_print(RELOC("...failed\n"));
}
#endif
+ /* If OpenFirmware version >= 3, then use quiesce call */
+ if (prom_version >= 3) {
+ prom_print(RELOC("Calling quiesce ...\n"));
+ call_prom(RELOC("quiesce"), 0, 0);
+ offset = reloc_offset();
+ phys = offset + KERNELBASE;
+ }
+
+#ifdef CONFIG_BOOTX_TEXT
+ if (!chrp && RELOC(disp_bi)) {
+ RELOC(prom_stdout) = 0;
+ clearscreen();
+ prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
+ prom_print(RELOC("booting...\n"));
+ }
+#endif
+
+ return phys;
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+__init static void
+prom_welcome(boot_infos_t* bi, unsigned long phys)
+{
+ unsigned long offset = reloc_offset();
+ unsigned long flags;
+ unsigned long pvr;
+
+ prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
+ prom_print(RELOC("\nstarted at : 0x"));
+ drawhex(phys);
+ prom_print(RELOC("\nlinked at : 0x"));
+ drawhex(KERNELBASE);
+ prom_print(RELOC("\nframe buffer at : 0x"));
+ drawhex((unsigned long)bi->dispDeviceBase);
+ prom_print(RELOC(" (phys), 0x"));
+ drawhex((unsigned long)bi->logicalDisplayBase);
+ prom_print(RELOC(" (log)"));
+ prom_print(RELOC("\nMSR : 0x"));
+ __asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
+ drawhex(flags);
+ __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
+ pvr >>= 16;
+ if (pvr > 1) {
+ prom_print(RELOC("\nHID0 : 0x"));
+ __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
+ drawhex(flags);
+ }
+ if (pvr == 8 || pvr == 12) {
+ prom_print(RELOC("\nICTC : 0x"));
+ __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
+ drawhex(flags);
+ }
+ prom_print(RELOC("\n\n"));
+}
+#endif
+
+static int prom_set_color(ihandle ih, int i, int r, int g, int b)
+{
+ struct prom_args prom_args;
+ unsigned long offset = reloc_offset();
+
+ prom_args.service = RELOC("call-method");
+ prom_args.nargs = 6;
+ prom_args.nret = 1;
+ prom_args.args[0] = RELOC("color!");
+ prom_args.args[1] = ih;
+ prom_args.args[2] = (void *) i;
+ prom_args.args[3] = (void *) b;
+ prom_args.args[4] = (void *) g;
+ prom_args.args[5] = (void *) r;
+ RELOC(prom)(&prom_args);
+ return (int) prom_args.args[6];
}
/*
@@ -573,6 +711,26 @@ check_display(unsigned long mem)
int i;
unsigned long offset = reloc_offset();
char type[16], *path;
+ static unsigned char default_colors[] = {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xaa,
+ 0x00, 0xaa, 0x00,
+ 0x00, 0xaa, 0xaa,
+ 0xaa, 0x00, 0x00,
+ 0xaa, 0x00, 0xaa,
+ 0xaa, 0xaa, 0x00,
+ 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0xff,
+ 0x55, 0xff, 0x55,
+ 0x55, 0xff, 0xff,
+ 0xff, 0x55, 0x55,
+ 0xff, 0x55, 0xff,
+ 0xff, 0xff, 0x55,
+ 0xff, 0xff, 0xff
+ };
+
+ RELOC(prom_disp_node) = 0;
for (node = 0; prom_next_node(&node); ) {
type[0] = 0;
@@ -595,6 +753,26 @@ check_display(unsigned long mem)
}
prom_print(RELOC("... ok\n"));
+ if (RELOC(prom_disp_node) == 0)
+ RELOC(prom_disp_node) = node;
+
+ /* Setup a useable color table when the appropriate
+ * method is available. Should update this to set-colors */
+ for (i = 0; i < 32; i++)
+ if (prom_set_color(ih, i, RELOC(default_colors)[i*3],
+ RELOC(default_colors)[i*3+1],
+ RELOC(default_colors)[i*3+2]) != 0)
+ break;
+
+#ifdef CONFIG_FB
+ for (i = 0; i < LINUX_LOGO_COLORS; i++)
+ if (prom_set_color(ih, i + 32,
+ RELOC(linux_logo_red)[i],
+ RELOC(linux_logo_green)[i],
+ RELOC(linux_logo_blue)[i]) != 0)
+ break;
+#endif /* CONFIG_FB */
+
/*
* If this display is the device that OF is using for stdout,
* move it to the front of the list.
@@ -614,6 +792,79 @@ check_display(unsigned long mem)
return ALIGN(mem);
}
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+#ifdef CONFIG_BOOTX_TEXT
+__init
+static void
+setup_disp_fake_bi(ihandle dp)
+{
+ unsigned int len;
+ int width = 640, height = 480, depth = 8, pitch;
+ unsigned address;
+ boot_infos_t* bi;
+ unsigned long offset = reloc_offset();
+
+ prom_print(RELOC("Initing fake screen\n"));
+
+ len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len));
+ if (len == 0)
+ prom_print(RELOC("Warning: assuming display depth = 8\n"));
+ else
+ depth = len;
+ width = len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &len, sizeof(len));
+ width = len;
+ if (width == 0) {
+ prom_print(RELOC("Failed to get width\n"));
+ return;
+ }
+ height = len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &len, sizeof(len));
+ height = len;
+ if (height == 0) {
+ prom_print(RELOC("Failed to get height\n"));
+ return;
+ }
+ pitch = len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len));
+ pitch = len;
+ if (pitch == 0) {
+ prom_print(RELOC("Failed to get pitch\n"));
+ return;
+ }
+ address = len = 0;
+ call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len));
+ address = len;
+ if (address == 0) {
+ prom_print(RELOC("Failed to get address\n"));
+ return;
+ }
+#if 0
+ /* kludge for valkyrie */
+ if (strcmp(dp->name, "valkyrie") == 0)
+ address += 0x1000;
+ }
+#endif
+
+ RELOC(disp_bi) = &fake_bi;
+ bi = PTRRELOC((&fake_bi));
+ RELOC(g_loc_X) = 0;
+ RELOC(g_loc_Y) = 0;
+ RELOC(g_max_loc_X) = width / 8;
+ RELOC(g_max_loc_Y) = height / 16;
+ bi->logicalDisplayBase = (unsigned char *)address;
+ bi->dispDeviceBase = (unsigned char *)address;
+ bi->dispDeviceRowBytes = pitch;
+ bi->dispDeviceDepth = depth;
+ bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+ bi->dispDeviceRect[2] = width;
+ bi->dispDeviceRect[3] = height;
+}
+#endif
+
__init
static int
prom_next_node(phandle *nodep)
@@ -748,6 +999,16 @@ void
finish_device_tree(void)
{
unsigned long mem = (unsigned long) klimit;
+ char* model;
+
+ /* Here, we decide if we'll use the interrupt-tree (new Core99 code) or not.
+ * This code was only tested with Core99 machines so far, but should be easily
+ * adapted to older newworld machines (iMac, B&W G3, Lombard).
+ */
+ model = get_property(allnodes, "model", 0);
+ if ((boot_infos == 0) && model && (strcmp(model, "PowerBook2,1") == 0
+ || strcmp(model, "PowerMac2,1") == 0 || strcmp(model, "PowerMac3,1") == 0))
+ use_of_interrupt_tree = 1;
mem = finish_node(allnodes, mem, NULL);
dev_tree_size = mem - (unsigned long) allnodes;
@@ -788,6 +1049,9 @@ finish_node(struct device_node *np, unsigned long mem_start,
if (ifunc != NULL) {
mem_start = ifunc(np, mem_start);
}
+ if (use_of_interrupt_tree) {
+ mem_start = finish_node_interrupts(np, mem_start);
+ }
/* the f50 sets the name to 'display' and 'compatible' to what we
* expect for the name -- Cort
@@ -834,6 +1098,133 @@ finish_node(struct device_node *np, unsigned long mem_start,
return mem_start;
}
+/* This routine walks the interrupt tree for a given device node and gather
+ * all necessary informations according to the draft interrupt mapping
+ * for CHRP. The current version was only tested on Apple "Core99" machines
+ * and may not handle cascaded controllers correctly.
+ */
+__init
+static unsigned long
+finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+{
+ /* Finish this node */
+ unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg;
+ phandle *parent;
+ struct device_node *node, *parent_node;
+ int l, isize, ipsize, asize, map_size, regpsize;
+
+ /* Currently, we don't look at all nodes with no "interrupts" property */
+ interrupts = (unsigned int *)get_property(np, "interrupts", &l);
+ if (interrupts == NULL)
+ return mem_start;
+ ipsize = l>>2;
+
+ reg = (unsigned int *)get_property(np, "reg", &l);
+ regpsize = l>>2;
+
+ /* We assume default interrupt cell size is 1 (bugus ?) */
+ isize = 1;
+ node = np;
+
+ do {
+ /* We adjust the cell size if the current parent contains an #interrupt-cells
+ * property */
+ isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l);
+ if (isizep)
+ isize = *isizep;
+
+ /* We don't do interrupt cascade (ISA) for now, we stop on the first
+ * controller found
+ */
+ if (get_property(node, "interrupt-controller", &l)) {
+ int i,j;
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = ipsize / isize;
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *interrupts++;
+ np->intrs[i].sense = 0;
+ if (isize > 1)
+ np->intrs[i].sense = *interrupts++;
+ for (j=2; j<isize; j++)
+ interrupts++;
+ }
+ return mem_start;
+ }
+ /* We lookup for an interrupt-map. This code can only handle one interrupt
+ * per device in the map. We also don't handle #address-cells in the parent
+ * I skip the pci node itself here, may not be necessary but I don't like it's
+ * reg property.
+ */
+ if (np != node)
+ map = (unsigned int *)get_property(node, "interrupt-map", &l);
+ else
+ map = NULL;
+ if (map && l) {
+ int i, found, temp_isize;
+ map_size = l>>2;
+ map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
+ asizep = (unsigned int *)get_property(node, "#address-cells", &l);
+ if (asizep && l == sizeof(unsigned int))
+ asize = *asizep;
+ else
+ asize = 0;
+ found = 0;
+ while(map_size>0 && !found) {
+ found = 1;
+ for (i=0; i<asize; i++) {
+ unsigned int mask = map_mask ? map_mask[i] : 0xffffffff;
+ if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i])))
+ found = 0;
+ map++;
+ map_size--;
+ }
+ for (i=0; i<isize; i++) {
+ unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff;
+ if ((mask & *map) != (mask & interrupts[i]))
+ found = 0;
+ map++;
+ map_size--;
+ }
+ parent = *((phandle *)(map));
+ map+=1; map_size-=1;
+ parent_node = find_phandle(parent);
+ temp_isize = isize;
+ if (parent_node) {
+ isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
+ if (isizep)
+ temp_isize = *isizep;
+ }
+ if (!found) {
+ map += temp_isize;
+ map_size-=temp_isize;
+ }
+ }
+ if (found) {
+ node = parent_node;
+ reg = NULL;
+ regpsize = 0;
+ interrupts = (unsigned int *)map;
+ ipsize = temp_isize*1;
+ continue;
+ }
+ }
+ /* We look for an explicit interrupt-parent.
+ */
+ parent = (phandle *)get_property(node, "interrupt-parent", &l);
+ if (parent && (l == sizeof(phandle)) &&
+ (parent_node = find_phandle(*parent))) {
+ node = parent_node;
+ continue;
+ }
+ /* Default, get real parent */
+ node = node->parent;
+ } while(node);
+
+ return mem_start;
+}
+
+
/*
* When BootX makes a copy of the device tree from the MacOS
* Name Registry, it is in the format we use but all of the pointers
@@ -892,6 +1283,9 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start)
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
/*
* If the pci host bridge has an interrupt-map property,
* look for our node in it.
@@ -901,14 +1295,28 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start)
get_property(np->parent, "interrupt-map", &ml)) != 0
&& (ip = (int *) get_property(np, "interrupts", &l)) != 0) {
unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00;
+ unsigned int cell_size;
+ struct device_node* np2;
+ /* This is hackish, but is only used for BootX booting */
+ cell_size = sizeof(struct pci_intr_map);
+ np2 = np->parent;
+ while(np2) {
+ if (device_is_compatible(np2, "uni-north")) {
+ cell_size += 4;
+ break;
+ }
+ np2 = np2->parent;
+ }
np->n_intrs = 0;
np->intrs = (struct interrupt_info *) mem_start;
- for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) {
- if (imp[i].addr.a_hi == devfn) {
- np->intrs[np->n_intrs].line = imp[i].intr;
- np->intrs[np->n_intrs].sense = 0;
+ for (i = 0; (ml -= cell_size) >= 0; ++i) {
+ if (imp->addr.a_hi == devfn) {
+ np->intrs[np->n_intrs].line = imp->intr;
+ np->intrs[np->n_intrs].sense = 0; /* FIXME */
++np->n_intrs;
}
+ imp = (struct pci_intr_map *)(((unsigned int)imp)
+ + cell_size);
}
if (np->n_intrs == 0)
np->intrs = 0;
@@ -965,6 +1373,9 @@ interpret_dbdma_props(struct device_node *np, unsigned long mem_start)
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
ip = (int *) get_property(np, "AAPL,interrupts", &l);
if (ip == 0)
ip = (int *) get_property(np, "interrupts", &l);
@@ -988,13 +1399,14 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start)
struct reg_property *rp;
struct address_range *adr;
unsigned long base_address;
- int i, l, *ip;
+ int i, l, keylargo, *ip;
struct device_node *db;
base_address = 0;
for (db = np->parent; db != NULL; db = db->parent) {
if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
base_address = db->addrs[0].address;
+ keylargo = device_is_compatible(db, "Keylargo");
break;
}
}
@@ -1014,6 +1426,9 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start)
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
ip = (int *) get_property(np, "interrupts", &l);
if (ip == 0)
ip = (int *) get_property(np, "AAPL,interrupts", &l);
@@ -1022,9 +1437,15 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start)
if (_machine == _MACH_Pmac) {
/* for the iMac */
np->n_intrs = l / sizeof(int);
+ /* Hack for BootX on Core99 */
+ if (keylargo)
+ np->n_intrs = np->n_intrs/2;
for (i = 0; i < np->n_intrs; ++i) {
np->intrs[i].line = *ip++;
- np->intrs[i].sense = 0;
+ if (keylargo)
+ np->intrs[i].sense = *ip++;
+ else
+ np->intrs[i].sense = 0;
}
} else {
/* CHRP machines */
@@ -1064,6 +1485,9 @@ interpret_isa_props(struct device_node *np, unsigned long mem_start)
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
ip = (int *) get_property(np, "interrupts", &l);
if (ip != 0) {
np->intrs = (struct interrupt_info *) mem_start;
@@ -1101,6 +1525,9 @@ interpret_root_props(struct device_node *np, unsigned long mem_start)
mem_start += i * sizeof(struct address_range);
}
+ if (use_of_interrupt_tree)
+ return mem_start;
+
ip = (int *) get_property(np, "AAPL,interrupts", &l);
if (ip == 0)
ip = (int *) get_property(np, "interrupts", &l);
@@ -1157,6 +1584,49 @@ find_type_devices(const char *type)
return head;
}
+/* Finds a device node given its PCI bus number, device number
+ * and function number
+ */
+__openfirmware
+struct device_node *
+find_pci_device_OFnode(unsigned char bus, unsigned char dev_fn)
+{
+ struct device_node* np;
+ unsigned int *reg;
+ int l;
+
+ for (np = allnodes; np != 0; np = np->allnext) {
+ char *pname = np->parent ?
+ (char *)get_property(np->parent, "name", &l) : 0;
+ if (pname && strcmp(pname, "mac-io") == 0)
+ continue;
+ reg = (unsigned int *) get_property(np, "reg", &l);
+ if (reg == 0 || l < sizeof(struct reg_property))
+ continue;
+ if (((reg[0] >> 8) & 0xff) == dev_fn && ((reg[0] >> 16) & 0xff) == bus)
+ break;
+ }
+ return np;
+}
+
+/*
+ * Returns all nodes linked together
+ */
+__openfirmware
+struct device_node *
+find_all_nodes(void)
+{
+ struct device_node *head, **prevp, *np;
+
+ prevp = &head;
+ for (np = allnodes; np != 0; np = np->allnext) {
+ *prevp = np;
+ prevp = &np->next;
+ }
+ *prevp = 0;
+ return head;
+}
+
/* Checks if the given "compat" string matches one of the strings in
* the device's "compatible" property
*/
@@ -1377,18 +1847,28 @@ abort()
prom_exit();
}
-#ifdef CONFIG_XMON
+#ifdef CONFIG_BOOTX_TEXT
+
+/* Here's a small text engine to use during early boot or for debugging purposes
+ *
+ * todo:
+ *
+ * - build some kind of vgacon with it to enable early printk
+ * - move to a separate file
+ * - add a few video driver hooks to keep in sync with display
+ * changes.
+ */
+
__init
void
map_bootx_text(void)
{
- if (boot_infos == 0)
+ if (disp_bi == 0)
return;
- boot_infos->logicalDisplayBase =
- ioremap((unsigned long) boot_infos->dispDeviceBase,
- boot_infos->dispDeviceRowBytes * boot_infos->dispDeviceRect[3]);
+ disp_bi->logicalDisplayBase =
+ ioremap((unsigned long) disp_bi->dispDeviceBase,
+ disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]);
}
-#endif /* CONFIG_XMON */
/* Calc the base address of a given point (x,y) */
__pmac
@@ -1410,7 +1890,7 @@ static void
clearscreen(void)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
unsigned long *base = (unsigned long *)calc_base(bi, 0, 0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
(bi->dispDeviceDepth >> 3)) >> 2;
@@ -1435,7 +1915,7 @@ static void
flushscreen(void)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
unsigned long *base = (unsigned long *)calc_base(bi, 0, 0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
(bi->dispDeviceDepth >> 3)) >> 2;
@@ -1452,14 +1932,12 @@ flushscreen(void)
}
}
-#ifdef CONFIG_BOOTX_TEXT
-
__pmac
static void
scrollscreen(void)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
unsigned long *src = (unsigned long *)calc_base(bi,0,16);
unsigned long *dst = (unsigned long *)calc_base(bi,0,0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
@@ -1563,19 +2041,20 @@ static void
draw_byte(unsigned char c, long locX, long locY)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
unsigned char *base = calc_base(bi, locX << 3, locY << 4);
unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16];
+ int rb = bi->dispDeviceRowBytes;
switch(bi->dispDeviceDepth) {
case 32:
- draw_byte_32(font, (unsigned long *)base);
+ draw_byte_32(font, (unsigned long *)base, rb);
break;
case 16:
- draw_byte_16(font, (unsigned long *)base);
+ draw_byte_16(font, (unsigned long *)base, rb);
break;
case 8:
- draw_byte_8(font, (unsigned long *)base);
+ draw_byte_8(font, (unsigned long *)base, rb);
break;
default:
break;
@@ -1613,15 +2092,12 @@ static unsigned long expand_bits_16[4] = {
__pmac
static void
-draw_byte_32(unsigned char *font, unsigned long *base)
+draw_byte_32(unsigned char *font, unsigned long *base, int rb)
{
- unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
int l, bits;
int fg = 0xFFFFFFFFUL;
int bg = 0x00000000UL;
-
for (l = 0; l < 16; ++l)
{
bits = *font++;
@@ -1633,19 +2109,18 @@ draw_byte_32(unsigned char *font, unsigned long *base)
base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
base[7] = (-(bits & 1) & fg) ^ bg;
- base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+ base = (unsigned long *) ((char *)base + rb);
}
}
__pmac
static void
-draw_byte_16(unsigned char *font, unsigned long *base)
+draw_byte_16(unsigned char *font, unsigned long *base, int rb)
{
- unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
int l, bits;
int fg = 0xFFFFFFFFUL;
int bg = 0x00000000UL;
+ unsigned long offset = reloc_offset();
unsigned long *eb = RELOC(expand_bits_16);
for (l = 0; l < 16; ++l)
@@ -1655,19 +2130,18 @@ draw_byte_16(unsigned char *font, unsigned long *base)
base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
base[3] = (eb[bits & 3] & fg) ^ bg;
- base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+ base = (unsigned long *) ((char *)base + rb);
}
}
__pmac
static void
-draw_byte_8(unsigned char *font, unsigned long *base)
+draw_byte_8(unsigned char *font, unsigned long *base, int rb)
{
- unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
int l, bits;
int fg = 0x0F0F0F0FUL;
int bg = 0x00000000UL;
+ unsigned long offset = reloc_offset();
unsigned long *eb = RELOC(expand_bits_8);
for (l = 0; l < 16; ++l)
@@ -1675,7 +2149,7 @@ draw_byte_8(unsigned char *font, unsigned long *base)
bits = *font++;
base[0] = (eb[bits >> 4] & fg) ^ bg;
base[1] = (eb[bits & 0xf] & fg) ^ bg;
- base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+ base = (unsigned long *) ((char *)base + rb);
}
}
@@ -2026,3 +2500,4 @@ static unsigned char vga_font[cmapsz] = {
};
#endif /* CONFIG_BOOTX_TEXT */
+
diff --git a/arch/ppc/kernel/semaphore.c b/arch/ppc/kernel/semaphore.c
index d630c80dc..f17bc16ce 100644
--- a/arch/ppc/kernel/semaphore.c
+++ b/arch/ppc/kernel/semaphore.c
@@ -137,3 +137,44 @@ int __down_trylock(struct semaphore * sem)
{
return waking_non_zero_trylock(sem);
}
+
+
+/*
+ * rw semaphores Ani Joshi <ajoshi@unixbox.com>
+ * based on alpha port by Andrea Arcangeli <andrea@suse.de>
+ */
+
+void down_read_failed(struct rw_semaphore *sem)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ do {
+ __set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ spin_unlock_irq(&sem->lock);
+ schedule();
+ spin_lock_irq(&sem->lock);
+ } while(sem->wr);
+
+ remove_wait_queue(&sem->wait, &wait);
+}
+
+void down_write_failed(struct rw_semaphore *sem)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ do {
+ __set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ spin_unlock_irq(&sem->lock);
+ schedule();
+ spin_lock_irq(&sem->lock);
+ } while(sem->rd || sem->wr);
+
+ remove_wait_queue(&sem->wait, &wait);
+}
+
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index dccb066ff..19ce0a25e 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -69,6 +69,13 @@ extern void gemini_init(unsigned long r3,
unsigned long r6,
unsigned long r7);
+#ifdef CONFIG_BOOTX_TEXT
+extern void map_bootx_text(void);
+#endif
+#ifdef CONFIG_XMON
+extern void xmon_map_scc(void);
+#endif
+
extern boot_infos_t *boot_infos;
char saved_command_line[256];
unsigned char aux_device_present;
@@ -261,7 +268,7 @@ int get_cpuinfo(char *buffer)
}
break;
case 0x000C:
- len += sprintf(len+buffer, "7400\n");
+ len += sprintf(len+buffer, "7400 (G4)\n");
break;
case 0x0020:
len += sprintf(len+buffer, "403G");
@@ -292,7 +299,7 @@ int get_cpuinfo(char *buffer)
* Assume here that all clock rates are the same in a
* smp system. -- Cort
*/
-#ifndef CONFIG_8xx
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
if ( have_of )
{
struct device_node *cpu_node;
@@ -316,7 +323,7 @@ int get_cpuinfo(char *buffer)
len += sprintf(len+buffer, "clock\t\t: %dMHz\n",
*fp / 1000000);
}
-#endif
+#endif /* !CONFIG_4xx && !CONFIG_8xx */
if (ppc_md.setup_residual != NULL)
{
@@ -410,8 +417,9 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
parse_bootinfo();
-
+
if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100);
+
#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
#ifndef CONFIG_MACH_SPECIFIC
/* if we didn't get any bootinfo telling us what we are... */
@@ -477,11 +485,12 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
char *p;
#ifdef CONFIG_BLK_DEV_INITRD
- if (r3 - KERNELBASE < 0x800000
- && r4 != 0 && r4 != 0xdeadbeef) {
+ if (r3 && r4 && r4 != 0xdeadbeef)
+ {
initrd_start = r3;
initrd_end = r3 + r4;
ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ initrd_below_start_ok = 1;
}
#endif
cmd_line[0] = 0;
@@ -519,6 +528,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
default:
printk("Unknown machine type in identify_machine!\n");
}
+
/* Check for nobats option (used in mapin_ram). */
if (strstr(cmd_line, "nobats")) {
extern int __map_without_bats;
@@ -567,9 +577,11 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
int parse_bootinfo(void)
{
struct bi_record *rec;
- extern char _end[];
+ extern char __bss_start[];
+ extern char *sysmap;
+ extern unsigned long sysmap_size;
- rec = (struct bi_record *)PAGE_ALIGN((ulong)_end);
+ rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20));
if ( rec->tag != BI_FIRST )
{
/*
@@ -577,11 +589,10 @@ int parse_bootinfo(void)
* we have the bootloader handle all the relocation and
* prom calls -- Cort
*/
- rec = (struct bi_record *)PAGE_ALIGN((ulong)_end+0x10000);
+ rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20));
if ( rec->tag != BI_FIRST )
return -1;
}
-
for ( ; rec->tag != BI_LAST ;
rec = (struct bi_record *)((ulong)rec + rec->size) )
{
@@ -591,6 +602,11 @@ int parse_bootinfo(void)
case BI_CMD_LINE:
memcpy(cmd_line, (void *)data, rec->size);
break;
+ case BI_SYSMAP:
+ sysmap = (char *)((data[0] >= (KERNELBASE)) ? data[0] :
+ (data[0]+KERNELBASE));
+ sysmap_size = data[1];
+ break;
#ifdef CONFIG_BLK_DEV_INITRD
case BI_INITRD:
initrd_start = data[0];
@@ -603,7 +619,6 @@ int parse_bootinfo(void)
have_of = data[1];
break;
#endif /* CONFIG_MACH_SPECIFIC */
-
}
}
@@ -613,7 +628,7 @@ int parse_bootinfo(void)
/* Checks "l2cr=xxxx" command-line option */
void ppc_setup_l2cr(char *str, int *ints)
{
- if ( (_get_PVR() >> 16) == 8)
+ if ( ((_get_PVR() >> 16) == 8) || ((_get_PVR() >> 16) == 12) )
{
unsigned long val = simple_strtoul(str, NULL, 0);
printk(KERN_INFO "l2cr set to %lx\n", val);
@@ -639,12 +654,21 @@ void __init setup_arch(char **cmdline_p)
extern char *klimit;
extern void do_init_bootmem(void);
+#ifdef CONFIG_BOOTX_TEXT
+ map_bootx_text();
+ prom_print("identify machine\n");
+#endif
+
#ifdef CONFIG_XMON
- extern void xmon_map_scc(void);
xmon_map_scc();
if (strstr(cmd_line, "xmon"))
xmon(0);
#endif /* CONFIG_XMON */
+ if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
+#if defined(CONFIG_KGDB)
+ set_debug_traps();
+ breakpoint();
+#endif
/* reboot on panic */
panic_timeout = 180;
@@ -653,16 +677,16 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_code = (unsigned long) _etext;
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = (unsigned long) klimit;
-
+
/* Save unparsed command line copy for /proc/cmdline */
strcpy(saved_command_line, cmd_line);
*cmdline_p = cmd_line;
/* set up the bootmem stuff with available memory */
do_init_bootmem();
+ if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
ppc_md.setup_arch();
- /* clear the progress line */
if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
}
diff --git a/arch/ppc/kernel/sleep.S b/arch/ppc/kernel/sleep.S
index 3ead7bd28..b73acd6ce 100644
--- a/arch/ppc/kernel/sleep.S
+++ b/arch/ppc/kernel/sleep.S
@@ -171,6 +171,11 @@ _GLOBAL(low_sleep_handler)
*/
wake_up:
+ /* Flash inval the instruction cache */
+ mfspr r3,HID0
+ ori r3,r3, HID0_ICFI
+ mtspr HID0,r3
+ isync
/* Restore the HID0 register. This turns on the L1 caches. */
subi r1,r1,SL_PC
lwz r3,SL_HID0(r1)
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
index 30bed889b..e1a3fdcbb 100644
--- a/arch/ppc/kernel/syscalls.c
+++ b/arch/ppc/kernel/syscalls.c
@@ -252,9 +252,14 @@ asmlinkage int sys_pause(void)
asmlinkage int sys_uname(struct old_utsname * name)
{
- if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
- return 0;
- return -EFAULT;
+ int err;
+
+ if (!name)
+ return -EFAULT;
+ down_read(&uts_sem);
+ err = copy_to_user(name, &system_utsname, sizeof (*name));
+ up(&uts_sem);
+ return err ? -EFAULT : 0;
}
asmlinkage int sys_olduname(struct oldold_utsname * name)
@@ -266,6 +271,7 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
return -EFAULT;
+ down_read(&uts_sem);
error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
@@ -277,6 +283,7 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
error = __put_user(0,name->machine+__OLD_UTS_LEN);
error = error ? -EFAULT : 0;
+ up(&uts_sem);
return error;
}
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 04b4e2d36..5cc34c5a5 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -128,6 +128,20 @@ MachineCheckException(struct pt_regs *regs)
_exception(SIGSEGV, regs);
}
+void
+SMIException(struct pt_regs *regs)
+{
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ {
+ debugger(regs);
+ return;
+ }
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("System Management Interrupt");
+}
+
#if defined(CONFIG_ALTIVEC)
void
AltiVecUnavailable(struct pt_regs *regs)
diff --git a/arch/ppc/kernel/walnut_setup.c b/arch/ppc/kernel/walnut_setup.c
new file mode 100644
index 000000000..284c732c1
--- /dev/null
+++ b/arch/ppc/kernel/walnut_setup.c
@@ -0,0 +1,295 @@
+/*
+ *
+ * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: walnut_setup.c
+ *
+ * Description:
+ * Architecture- / platform-specific boot-time initialization code for
+ * the IBM PowerPC 403GP "Walnut" evaluation board. Adapted from original
+ * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ * <dan@net4x.com>.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+
+#include <asm/processor.h>
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+
+#include "local_irq.h"
+#include "ppc4xx_pic.h"
+#include "time.h"
+#include "walnut_setup.h"
+
+
+/* Function Prototypes */
+
+extern void abort(void);
+
+/* Global Variables */
+
+unsigned char __res[sizeof(bd_t)];
+
+
+/*
+ * void __init walnut_init()
+ *
+ * Description:
+ * This routine...
+ *
+ * Input(s):
+ * r3 - Optional pointer to a board information structure.
+ * r4 - Optional pointer to the physical starting address of the init RAM
+ * disk.
+ * r5 - Optional pointer to the physical ending address of the init RAM
+ * disk.
+ * r6 - Optional pointer to the physical starting address of any kernel
+ * command-line parameters.
+ * r7 - Optional pointer to the physical ending address of any kernel
+ * command-line parameters.
+ *
+ * Output(s):
+ * N/A
+ *
+ * Returns:
+ * N/A
+ *
+ */
+void __init
+walnut_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+ }
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+ /*
+ * If the init RAM disk has been configured in, and there's a valid
+ * starting address for it, set it up.
+ */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Copy the kernel command line arguments to a safe place. */
+
+ if (r6) {
+ *(char *)(r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6 + KERNELBASE));
+ }
+
+ /* Initialize machine-dependency vectors */
+
+ ppc_md.setup_arch = walnut_setup_arch;
+ ppc_md.setup_residual = walnut_setup_residual;
+ ppc_md.get_cpuinfo = NULL;
+ ppc_md.irq_cannonicalize = NULL;
+ ppc_md.init_IRQ = walnut_init_IRQ;
+ ppc_md.get_irq = walnut_get_irq;
+ ppc_md.init = NULL;
+
+ ppc_md.restart = walnut_restart;
+ ppc_md.power_off = walnut_power_off;
+ ppc_md.halt = walnut_halt;
+
+ ppc_md.time_init = walnut_time_init;
+ ppc_md.set_rtc_time = walnut_set_rtc_time;
+ ppc_md.get_rtc_time = walnut_get_rtc_time;
+ ppc_md.calibrate_decr = walnut_calibrate_decr;
+
+ ppc_md.kbd_setkeycode = NULL;
+ ppc_md.kbd_getkeycode = NULL;
+ ppc_md.kbd_translate = NULL;
+ ppc_md.kbd_unexpected_up = NULL;
+ ppc_md.kbd_leds = NULL;
+ ppc_md.kbd_init_hw = NULL;
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+ ppc_md.ppc_kbd_sysrq_xlate = NULL;
+#endif
+
+ return;
+}
+
+/*
+ * Document me.
+ */
+void __init
+walnut_setup_arch(void)
+{
+ /* XXX - Implement me */
+}
+
+/*
+ * int walnut_setup_residual()
+ *
+ * Description:
+ * This routine pretty-prints the platform's internal CPU and bus clock
+ * frequencies into the buffer for usage in /proc/cpuinfo.
+ *
+ * Input(s):
+ * *buffer - Buffer into which CPU and bus clock frequencies are to be
+ * printed.
+ *
+ * Output(s):
+ * *buffer - Buffer with the CPU and bus clock frequencies.
+ *
+ * Returns:
+ * The number of bytes copied into 'buffer' if OK, otherwise zero or less
+ * on error.
+ */
+int
+walnut_setup_residual(char *buffer)
+{
+ int len = 0;
+ bd_t *bp = (bd_t *)__res;
+
+ len += sprintf(len + buffer,
+ "clock\t\t: %dMHz\n"
+ "bus clock\t\t: %dMHz\n",
+ bp->bi_intfreq / 1000000,
+ bp->bi_busfreq / 1000000);
+
+ return (len);
+}
+
+/*
+ * Document me.
+ */
+void __init
+walnut_init_IRQ(void)
+{
+ int i;
+
+ ppc4xx_pic_init();
+
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc[i].handler = ppc4xx_pic;
+ }
+
+ return;
+}
+
+/*
+ * Document me.
+ */
+int
+walnut_get_irq(struct pt_regs *regs)
+{
+ return (ppc4xx_pic_get_irq(regs));
+}
+
+/*
+ * Document me.
+ */
+void
+walnut_restart(char *cmd)
+{
+ abort();
+}
+
+/*
+ * Document me.
+ */
+void
+walnut_power_off(void)
+{
+ walnut_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void
+walnut_halt(void)
+{
+ walnut_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void __init
+walnut_time_init(void)
+{
+ /* XXX - Implement me */
+}
+
+/*
+ * Document me.
+ */
+int __init
+walnut_set_rtc_time(unsigned long time)
+{
+ /* XXX - Implement me */
+
+ return (0);
+}
+
+/*
+ * Document me.
+ */
+unsigned long __init
+walnut_get_rtc_time(void)
+{
+ /* XXX - Implement me */
+
+ return (0);
+}
+
+/*
+ * void __init walnut_calibrate_decr()
+ *
+ * Description:
+ * This routine retrieves the internal processor frequency from the board
+ * information structure, sets up the kernel timer decrementer based on
+ * that value, enables the 403 programmable interval timer (PIT) and sets
+ * it up for auto-reload.
+ *
+ * Input(s):
+ * N/A
+ *
+ * Output(s):
+ * N/A
+ *
+ * Returns:
+ * N/A
+ *
+ */
+void __init
+walnut_calibrate_decr(void)
+{
+ unsigned int freq;
+ bd_t *bip = (bd_t *)__res;
+
+ freq = bip->bi_intfreq;
+
+ decrementer_count = freq / HZ;
+ count_period_num = 1;
+ count_period_den = freq;
+
+ /* Enable the PIT and set auto-reload of its value */
+
+ mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
+
+ /* Clear any pending timer interrupts */
+
+ mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
+}
diff --git a/arch/ppc/kernel/walnut_setup.h b/arch/ppc/kernel/walnut_setup.h
new file mode 100644
index 000000000..a6e905333
--- /dev/null
+++ b/arch/ppc/kernel/walnut_setup.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: walnut_setup.c
+ *
+ * Description:
+ * Architecture- / platform-specific boot-time initialization code for
+ * the IBM PowerPC 405GP "Walnut" evaluation board. Adapted from original
+ * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
+ * <dan@netx4.com>.
+ *
+ */
+
+#ifndef __WALNUT_SETUP_H__
+#define __WALNUT_SETUP_H__
+
+#include <asm/ptrace.h>
+#include <asm/board.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned char __res[sizeof(bd_t)];
+
+extern void walnut_init(unsigned long r3,
+ unsigned long ird_start,
+ unsigned long ird_end,
+ unsigned long cline_start,
+ unsigned long cline_end);
+extern void walnut_setup_arch(void);
+extern int walnut_setup_residual(char *buffer);
+extern void walnut_init_IRQ(void);
+extern int walnut_get_irq(struct pt_regs *regs);
+extern void walnut_restart(char *cmd);
+extern void walnut_power_off(void);
+extern void walnut_halt(void);
+extern void walnut_time_init(void);
+extern int walnut_set_rtc_time(unsigned long now);
+extern unsigned long walnut_get_rtc_time(void);
+extern void walnut_calibrate_decr(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WALNUT_SETUP_H__ */