summaryrefslogtreecommitdiff
path: root/src/arch/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/ppc')
-rw-r--r--src/arch/ppc/include/arch/cpu.h57
-rw-r--r--src/arch/ppc/include/arch/pci_ops.h8
-rw-r--r--src/arch/ppc/lib/Config.lb4
-rw-r--r--src/arch/ppc/lib/c_start.S2
-rw-r--r--src/arch/ppc/lib/cpu.c29
-rw-r--r--src/arch/ppc/lib/div64.S58
-rw-r--r--src/arch/ppc/lib/pci_ops.c105
-rw-r--r--src/arch/ppc/lib/pci_ppc_conf1_ops.c46
8 files changed, 194 insertions, 115 deletions
diff --git a/src/arch/ppc/include/arch/cpu.h b/src/arch/ppc/include/arch/cpu.h
index 48293b2425..e0ed4ff66a 100644
--- a/src/arch/ppc/include/arch/cpu.h
+++ b/src/arch/ppc/include/arch/cpu.h
@@ -1,3 +1,60 @@
+#ifndef ARCH_CPU_H
+#define ARCH_CPU_H
/*
* this should probably integrate code from src/arch/ppc/lib/cpuid.c
*/
+
+struct cpu_device_id {
+ unsigned pvr;
+};
+
+struct cpu_driver {
+ struct device_operations *ops;
+ struct cpu_device_id *id_table;
+};
+
+#ifndef STACK_SIZE
+#error STACK_SIZE not defined
+#endif
+
+/* The basic logic comes from the Linux kernel.
+ * The invariant is that (1 << 31 - STACK_BITS) == STACK_SIZE
+ * I wish there was simpler way to support multiple stack sizes.
+ * Oh well.
+ */
+#if STACK_SIZE == 4096
+#define STACK_BITS "19"
+#elif STACK_SIZE == 8192
+#define STACK_BITS "18"
+#elif STACK_SIZE == 16384
+#define STACK_BITS "17"
+#elif STACK_SIZE == 32768
+#define STACK_BITS "16"
+#elif STACK_SIZE == 65536
+#define STACK_BITS "15"
+#else
+#error Unimplemented stack size
+#endif
+
+
+struct cpu_info {
+ struct device *cpu;
+ unsigned long index;
+};
+
+
+static inline struct cpu_info *cpu_info(void)
+{
+ struct cpu_info *ci;
+ __asm__("rlwinm %0,1,0,0," STACK_BITS : "=r"(ci));
+ return ci;
+}
+
+static inline unsigned long cpu_index(void)
+{
+ struct cpu_info *ci;
+ ci = cpu_info();
+ return ci->index;
+}
+
+#endif /* ARCH_CPU_H */
diff --git a/src/arch/ppc/include/arch/pci_ops.h b/src/arch/ppc/include/arch/pci_ops.h
index 6f9c3af3af..95f8941e42 100644
--- a/src/arch/ppc/include/arch/pci_ops.h
+++ b/src/arch/ppc/include/arch/pci_ops.h
@@ -1,6 +1,6 @@
-#ifndef ARCH_I386_PCI_OPS_H
-#define ARCH_I386_PCI_OPS_H
+#ifndef ARCH_PPC_PCI_OPS_H
+#define ARCH_PPC_PCI_OPS_H
-void pci_set_method(void);
+const struct pci_bus_operations pci_ppc_conf1;
-#endif /* ARCH_I386_PCI_OPS_H */
+#endif /* ARCH_PPC_PCI_OPS_H */
diff --git a/src/arch/ppc/lib/Config.lb b/src/arch/ppc/lib/Config.lb
index 0c5aac9d5b..e501592683 100644
--- a/src/arch/ppc/lib/Config.lb
+++ b/src/arch/ppc/lib/Config.lb
@@ -1,15 +1,17 @@
object c_start.S
object setup.o
-object pci_ops.o
+object pci_ppc_conf1_ops.o
object pci_dev.o
object timer.o
object cpuid.o
object cpu.o
object timebase.S
object floats.S
+object div64.S
initobject pci_dev.o
initobject printk_init.o
initobject timebase.S
initobject timer.o
initobject setup.o
initobject floats.S
+initobject div64.S
diff --git a/src/arch/ppc/lib/c_start.S b/src/arch/ppc/lib/c_start.S
index 3fcf840615..d0d2a8f3d7 100644
--- a/src/arch/ppc/lib/c_start.S
+++ b/src/arch/ppc/lib/c_start.S
@@ -17,6 +17,8 @@
_start:
/*
* init stack pointer to real ram now that memory is on
+ * Note: We use the last 8 bytes on the stack to hold struct cpu_info,
+ * Which are initialized to zero as we clear the stack.
*/
li r0, 0
lis r1, _estack@ha
diff --git a/src/arch/ppc/lib/cpu.c b/src/arch/ppc/lib/cpu.c
index adf5358c28..3b6a256908 100644
--- a/src/arch/ppc/lib/cpu.c
+++ b/src/arch/ppc/lib/cpu.c
@@ -1,12 +1,32 @@
#include <console/console.h>
#include <arch/io.h>
#include <string.h>
+#include <device/device.h>
#include <cpu/cpu.h>
#include <cpu/ppc/cpuid.h>
#include "ppc.h"
#include "ppcreg.h"
-#error "FIXME what should call cpu_initialize?"
+#if 0
+static void set_cpu_ops(struct device *cpu)
+{
+ struct cpu_driver *driver;
+ cpu->ops = 0;
+ for (driver = cpu_drivers; driver < ecpu_drivers; driver++) {
+ struct cpu_device_id *id;
+ for(id = driver->id_table; id->pvr != 0; id++) {
+ if (cpu->device == id->pvr)
+ {
+ goto found;
+ }
+ }
+ }
+ die("Unknown cpu");
+ return;
+ found:
+ cpu->ops = driver->ops;
+}
+#endif
void cpu_initialize(void)
{
@@ -27,7 +47,7 @@ void cpu_initialize(void)
}
/* Find what type of cpu we are dealing with */
- cpu->vendor 0; /* PPC cpus do not have a vendor field */
+ cpu->vendor = 0; /* PPC cpus do not have a vendor field */
cpu->device = ppc_getpvr();
display_cpuid(cpu);
@@ -44,7 +64,6 @@ void cpu_initialize(void)
#endif
/* Turn on caching if we haven't already */
- printk_info("CPU #%d Initialized\n", processor_id);
- return processor_id;
+ printk_info("CPU #%d Initialized\n", info->index);
+ return;
}
-
diff --git a/src/arch/ppc/lib/div64.S b/src/arch/ppc/lib/div64.S
new file mode 100644
index 0000000000..48047747e0
--- /dev/null
+++ b/src/arch/ppc/lib/div64.S
@@ -0,0 +1,58 @@
+/*
+ * Divide a 64-bit unsigned number by a 32-bit unsigned number.
+ * This routine assumes that the top 32 bits of the dividend are
+ * non-zero to start with.
+ * On entry, r3 points to the dividend, which get overwritten with
+ * the 64-bit quotient, and r4 contains the divisor.
+ * On exit, r3 contains the remainder.
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <ppc_asm.tmpl>
+
+ .globl __div64_32
+__div64_32:
+ lwz r5,0(r3) # get the dividend into r5/r6
+ lwz r6,4(r3)
+ cmplw r5,r4
+ li r7,0
+ li r8,0
+ blt 1f
+ divwu r7,r5,r4 # if dividend.hi >= divisor,
+ mullw r0,r7,r4 # quotient.hi = dividend.hi / divisor
+ subf. r5,r0,r5 # dividend.hi %= divisor
+ beq 3f
+1: mr r11,r5 # here dividend.hi != 0
+ andis. r0,r5,0xc000
+ bne 2f
+ cntlzw r0,r5 # we are shifting the dividend right
+ li r10,-1 # to make it < 2^32, and shifting
+ srw r10,r10,r0 # the divisor right the same amount,
+ add r9,r4,r10 # rounding up (so the estimate cannot
+ andc r11,r6,r10 # ever be too large, only too small)
+ andc r9,r9,r10
+ or r11,r5,r11
+ rotlw r9,r9,r0
+ rotlw r11,r11,r0
+ divwu r11,r11,r9 # then we divide the shifted quantities
+2: mullw r10,r11,r4 # to get an estimate of the quotient,
+ mulhwu r9,r11,r4 # multiply the estimate by the divisor,
+ subfc r6,r10,r6 # take the product from the divisor,
+ add r8,r8,r11 # and add the estimate to the accumulated
+ subfe. r5,r9,r5 # quotient
+ bne 1b
+3: cmplw r6,r4
+ blt 4f
+ divwu r0,r6,r4 # perform the remaining 32-bit division
+ mullw r10,r0,r4 # and get the remainder
+ add r8,r8,r0
+ subf r6,r10,r6
+4: stw r7,0(r3) # return the quotient in *r3
+ stw r8,4(r3)
+ mr r3,r6 # return the remainder in r3
+ blr
diff --git a/src/arch/ppc/lib/pci_ops.c b/src/arch/ppc/lib/pci_ops.c
deleted file mode 100644
index 1e72fb0599..0000000000
--- a/src/arch/ppc/lib/pci_ops.c
+++ /dev/null
@@ -1,105 +0,0 @@
-#include <console/console.h>
-#include <arch/pciconf.h>
-#include <device/pci.h>
-#include <device/pci_ids.h>
-#include <device/pci_ops.h>
-
-static const struct pci_ops *conf;
-struct pci_ops {
- uint8_t (*read8) (uint8_t bus, int devfn, int where);
- uint16_t (*read16) (uint8_t bus, int devfn, int where);
- uint32_t (*read32) (uint8_t bus, int devfn, int where);
- int (*write8) (uint8_t bus, int devfn, int where, uint8_t val);
- int (*write16) (uint8_t bus, int devfn, int where, uint16_t val);
- int (*write32) (uint8_t bus, int devfn, int where, uint32_t val);
-};
-
-struct pci_ops pci_direct_ppc;
-
-/*
- * Before we decide to use direct hardware access mechanisms, we try to do some
- * trivial checks to ensure it at least _seems_ to be working -- we just test
- * whether bus 00 contains a host bridge (this is similar to checking
- * techniques used in XFree86, but ours should be more reliable since we
- * attempt to make use of direct access hints provided by the PCI BIOS).
- *
- * This should be close to trivial, but it isn't, because there are buggy
- * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
- */
-static int pci_sanity_check(const struct pci_ops *o)
-{
- uint16_t class, vendor;
- uint8_t bus;
- int devfn;
-#define PCI_CLASS_BRIDGE_HOST 0x0600
-#define PCI_CLASS_DISPLAY_VGA 0x0300
-#define PCI_VENDOR_ID_COMPAQ 0x0e11
-#define PCI_VENDOR_ID_INTEL 0x8086
-#define PCI_VENDOR_ID_MOTOROLA 0x1057
-#define PCI_VENDOR_ID_IBM 0x1014
-
- for (bus = 0, devfn = 0; devfn < 0x100; devfn++) {
- class = o->read16(bus, devfn, PCI_CLASS_DEVICE);
- vendor = o->read16(bus, devfn, PCI_VENDOR_ID);
- if (((class == PCI_CLASS_BRIDGE_HOST) ||
- (class == PCI_CLASS_DISPLAY_VGA)) ||
- ((vendor == PCI_VENDOR_ID_INTEL) ||
- (vendor == PCI_VENDOR_ID_COMPAQ) ||
- (vendor == PCI_VENDOR_ID_MOTOROLA) ||
- (vendor == PCI_VENDOR_ID_IBM))) {
- return 1;
- }
- }
-
- printk_err("PCI: Sanity check failed\n");
- return 0;
-}
-
-uint8_t pci_read_config8(device_t dev, unsigned where)
-{
- return conf->read8(dev->bus->secondary, dev->path.u.pci.devfn, where);
-}
-
-uint16_t pci_read_config16(struct device *dev, unsigned where)
-{
- return conf->read16(dev->bus->secondary, dev->path.u.pci.devfn, where);
-}
-
-uint32_t pci_read_config32(struct device *dev, unsigned where)
-{
- return conf->read32(dev->bus->secondary, dev->path.u.pci.devfn, where);
-}
-
-void pci_write_config8(struct device *dev, unsigned where, uint8_t val)
-{
- conf->write8(dev->bus->secondary, dev->path.u.pci.devfn, where, val);
-}
-
-void pci_write_config16(struct device *dev, unsigned where, uint16_t val)
-{
- conf->write16(dev->bus->secondary, dev->path.u.pci.devfn, where, val);
-}
-
-void pci_write_config32(struct device *dev, unsigned where, uint32_t val)
-{
- conf->write32(dev->bus->secondary, dev->path.u.pci.devfn, where, val);
-}
-
-/** Set the method to be used for PCI
- */
-void pci_set_method(void)
-{
- conf = &pci_direct_ppc;
- pci_sanity_check(conf);
-}
-
-struct pci_ops pci_direct_ppc =
-{
- pci_ppc_read_config8,
- pci_ppc_read_config16,
- pci_ppc_read_config32,
- pci_ppc_write_config8,
- pci_ppc_write_config16,
- pci_ppc_write_config32
-};
-
diff --git a/src/arch/ppc/lib/pci_ppc_conf1_ops.c b/src/arch/ppc/lib/pci_ppc_conf1_ops.c
new file mode 100644
index 0000000000..12e4529784
--- /dev/null
+++ b/src/arch/ppc/lib/pci_ppc_conf1_ops.c
@@ -0,0 +1,46 @@
+#include <console/console.h>
+#include <arch/pciconf.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+
+static uint8_t ppc_conf1_read_config8(struct bus *pbus, unsigned char bus, int devfn, int where)
+{
+ return pci_ppc_read_config8(bus, devfn, where);
+}
+
+static uint16_t ppc_conf1_read_config16(struct bus *pbus, unsigned char bus, int devfn, int where)
+{
+ return pci_ppc_read_config16(bus, devfn, where);
+}
+
+static uint32_t ppc_conf1_read_config32(struct bus *pbus, unsigned char bus, int devfn, int where)
+{
+ return pci_ppc_read_config32(bus, devfn, where);
+}
+
+static void ppc_conf1_write_config8(struct bus *pbus, unsigned char bus, int devfn, int where, uint8_t val)
+{
+ pci_ppc_write_config8(bus, devfn, where, val);
+}
+
+static void ppc_conf1_write_config16(struct bus *pbus, unsigned char bus, int devfn, int where, uint16_t val)
+{
+ pci_ppc_write_config16(bus, devfn, where, val);
+}
+
+static void ppc_conf1_write_config32(struct bus *pbus, unsigned char bus, int devfn, int where, uint32_t val)
+{
+ pci_ppc_write_config32(bus, devfn, where, val);
+}
+
+const struct pci_bus_operations pci_ppc_conf1 =
+{
+ .read8 = ppc_conf1_read_config8,
+ .read16 = ppc_conf1_read_config16,
+ .read32 = ppc_conf1_read_config32,
+ .write8 = ppc_conf1_write_config8,
+ .write16 = ppc_conf1_write_config16,
+ .write32 = ppc_conf1_write_config32,
+};