diff options
Diffstat (limited to 'src/arch/ppc')
-rw-r--r-- | src/arch/ppc/include/arch/cpu.h | 57 | ||||
-rw-r--r-- | src/arch/ppc/include/arch/pci_ops.h | 8 | ||||
-rw-r--r-- | src/arch/ppc/lib/Config.lb | 4 | ||||
-rw-r--r-- | src/arch/ppc/lib/c_start.S | 2 | ||||
-rw-r--r-- | src/arch/ppc/lib/cpu.c | 29 | ||||
-rw-r--r-- | src/arch/ppc/lib/div64.S | 58 | ||||
-rw-r--r-- | src/arch/ppc/lib/pci_ops.c | 105 | ||||
-rw-r--r-- | src/arch/ppc/lib/pci_ppc_conf1_ops.c | 46 |
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, +}; |