summaryrefslogtreecommitdiff
path: root/src/arch/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/ppc')
-rw-r--r--src/arch/ppc/boot/boot.c83
-rw-r--r--src/arch/ppc/boot/linuxbios_table.c285
-rw-r--r--src/arch/ppc/include/arch/boot/boot.h8
-rw-r--r--src/arch/ppc/include/arch/io.h192
-rw-r--r--src/arch/ppc/include/arch/pirq_routing.h54
-rw-r--r--src/arch/ppc/include/bitops.h22
-rw-r--r--src/arch/ppc/include/ppc.h21
-rw-r--r--src/arch/ppc/include/ppc_asm.tmpl293
-rw-r--r--src/arch/ppc/include/ppcreg.h128
-rw-r--r--src/arch/ppc/include/stddef.h15
-rw-r--r--src/arch/ppc/include/stdint.h52
-rw-r--r--src/arch/ppc/include/timer.h13
-rw-r--r--src/arch/ppc/lib/c_start.S109
-rw-r--r--src/arch/ppc/lib/floats.S45
-rw-r--r--src/arch/ppc/lib/floats.inc43
-rw-r--r--src/arch/ppc/lib/setup.c130
-rw-r--r--src/arch/ppc/lib/timebase.S13
-rw-r--r--src/arch/ppc/lib/timer.c31
18 files changed, 1537 insertions, 0 deletions
diff --git a/src/arch/ppc/boot/boot.c b/src/arch/ppc/boot/boot.c
new file mode 100644
index 0000000000..79eea965b3
--- /dev/null
+++ b/src/arch/ppc/boot/boot.c
@@ -0,0 +1,83 @@
+#include <ip_checksum.h>
+#include <boot/elf.h>
+#include <boot/elf_boot.h>
+#include <string.h>
+#include <printk.h>
+
+
+#ifndef CMD_LINE
+#define CMD_LINE ""
+#endif
+
+
+
+#define UPSZ(X) ((sizeof(X) + 3) &~3)
+
+static struct {
+ Elf_Bhdr hdr;
+ Elf_Nhdr ft_hdr;
+ unsigned char ft_desc[UPSZ(FIRMWARE_TYPE)];
+ Elf_Nhdr bl_hdr;
+ unsigned char bl_desc[UPSZ(BOOTLOADER)];
+ Elf_Nhdr blv_hdr;
+ unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
+ Elf_Nhdr cmd_hdr;
+ unsigned char cmd_desc[UPSZ(CMD_LINE)];
+} elf_boot_notes = {
+ .hdr = {
+ .b_signature = 0x0E1FB007,
+ .b_size = sizeof(elf_boot_notes),
+ .b_checksum = 0,
+ .b_records = 4,
+ },
+ .ft_hdr = {
+ .n_namesz = 0,
+ .n_descsz = sizeof(FIRMWARE_TYPE),
+ .n_type = EBN_FIRMWARE_TYPE,
+ },
+ .ft_desc = FIRMWARE_TYPE,
+ .bl_hdr = {
+ .n_namesz = 0,
+ .n_descsz = sizeof(BOOTLOADER),
+ .n_type = EBN_BOOTLOADER_NAME,
+ },
+ .bl_desc = BOOTLOADER,
+ .blv_hdr = {
+ .n_namesz = 0,
+ .n_descsz = sizeof(BOOTLOADER_VERSION),
+ .n_type = EBN_BOOTLOADER_VERSION,
+ },
+ .blv_desc = BOOTLOADER_VERSION,
+ .cmd_hdr = {
+ .n_namesz = 0,
+ .n_descsz = sizeof(CMD_LINE),
+ .n_type = EBN_COMMAND_LINE,
+ },
+ .cmd_desc = CMD_LINE,
+};
+
+
+int elf_check_arch(Elf_ehdr *ehdr)
+{
+ return (
+ (ehdr->e_machine == EM_PPC) &&
+ (ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
+ (ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
+ );
+
+}
+
+void jmp_to_elf_entry(void *entry, unsigned long buffer)
+{
+ void (*kernel_entry)(void);
+ kernel_entry = entry;
+
+ /* On ppc we don't currently support loading over LinuxBIOS.
+ * So ignore the buffer.
+ */
+
+ /* Jump to kernel */
+ kernel_entry();
+}
+
+
diff --git a/src/arch/ppc/boot/linuxbios_table.c b/src/arch/ppc/boot/linuxbios_table.c
new file mode 100644
index 0000000000..253a5e5b7f
--- /dev/null
+++ b/src/arch/ppc/boot/linuxbios_table.c
@@ -0,0 +1,285 @@
+#include <mem.h>
+#include <ip_checksum.h>
+#include <boot/linuxbios_tables.h>
+#include <boot/linuxbios_table.h>
+#include <printk.h>
+#include <string.h>
+#include <version.h>
+
+
+struct lb_header *lb_table_init(unsigned long addr)
+{
+ struct lb_header *header;
+
+ /* 16 byte align the address */
+ addr += 15;
+ addr &= ~15;
+
+ header = (void *)addr;
+ header->signature[0] = 'L';
+ header->signature[1] = 'B';
+ header->signature[2] = 'I';
+ header->signature[3] = 'O';
+ header->header_bytes = sizeof(*header);
+ header->header_checksum = 0;
+ header->table_bytes = 0;
+ header->table_checksum = 0;
+ header->table_entries = 0;
+ return header;
+}
+
+struct lb_record *lb_first_record(struct lb_header *header)
+{
+ struct lb_record *rec;
+ rec = (void *)(((char *)header) + sizeof(*header));
+ return rec;
+}
+
+struct lb_record *lb_last_record(struct lb_header *header)
+{
+ struct lb_record *rec;
+ rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes);
+ return rec;
+}
+
+struct lb_record *lb_next_record(struct lb_record *rec)
+{
+ rec = (void *)(((char *)rec) + rec->size);
+ return rec;
+}
+
+struct lb_record *lb_new_record(struct lb_header *header)
+{
+ struct lb_record *rec;
+ rec = lb_last_record(header);
+ if (header->table_entries) {
+ header->table_bytes += rec->size;
+ }
+ rec = lb_last_record(header);
+ header->table_entries++;
+ rec->tag = LB_TAG_UNUSED;
+ rec->size = sizeof(*rec);
+ return rec;
+}
+
+
+struct lb_memory *lb_memory(struct lb_header *header)
+{
+ struct lb_record *rec;
+ struct lb_memory *mem;
+ rec = lb_new_record(header);
+ mem = (struct lb_memory *)rec;
+ mem->tag = LB_TAG_MEMORY;
+ mem->size = sizeof(*mem);
+ return mem;
+}
+
+struct lb_mainboard *lb_mainboard(struct lb_header *header)
+{
+ struct lb_record *rec;
+ struct lb_mainboard *mainboard;
+ rec = lb_new_record(header);
+ mainboard = (struct lb_mainboard *)rec;
+ mainboard->tag = LB_TAG_MAINBOARD;
+
+ mainboard->size = (sizeof(*mainboard) +
+ strlen(mainboard_vendor) + 1 +
+ strlen(mainboard_part_number) + 1 +
+ 3) & ~3;
+
+ mainboard->vendor_idx = 0;
+ mainboard->part_number_idx = strlen(mainboard_vendor) + 1;
+
+ memcpy(mainboard->strings + mainboard->vendor_idx,
+ mainboard_vendor, strlen(mainboard_vendor) + 1);
+ memcpy(mainboard->strings + mainboard->part_number_idx,
+ mainboard_part_number, strlen(mainboard_part_number) + 1);
+
+ return mainboard;
+}
+
+void lb_strings(struct lb_header *header)
+{
+ static const struct {
+ uint32_t tag;
+ const uint8_t *string;
+ } strings[] = {
+ { LB_TAG_VERSION, linuxbios_version, },
+ { LB_TAG_EXTRA_VERSION, linuxbios_extra_version, },
+ { LB_TAG_BUILD, linuxbios_build, },
+ { LB_TAG_COMPILE_TIME, linuxbios_compile_time, },
+ { LB_TAG_COMPILE_BY, linuxbios_compile_by, },
+ { LB_TAG_COMPILE_HOST, linuxbios_compile_host, },
+ { LB_TAG_COMPILE_DOMAIN, linuxbios_compile_domain, },
+ { LB_TAG_COMPILER, linuxbios_compiler, },
+ { LB_TAG_LINKER, linuxbios_linker, },
+ { LB_TAG_ASSEMBLER, linuxbios_assembler, },
+ };
+ int i;
+ for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
+ struct lb_record *rec;
+ struct lb_string *str;
+ size_t len;
+ rec = lb_new_record(header);
+ str = (struct lb_string *)rec;
+ len = strlen(strings[i].string);
+ str->tag = strings[i].tag;
+ str->size = (sizeof(*rec) + len + 1 + 3) & ~3;
+ memcpy(str->string, strings[i].string, len+1);
+ }
+
+}
+
+/* Some version of gcc have problems with 64 bit types so
+ * take an unsigned long instead of a uint64_t for now.
+ */
+void lb_memory_range(struct lb_memory *mem,
+ uint32_t type, unsigned long start, unsigned long size)
+{
+ int entries;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+ mem->map[entries].start = start;
+ mem->map[entries].size = size;
+ mem->map[entries].type = type;
+ mem->size += sizeof(mem->map[0]);
+}
+
+static void lb_memory_rangek(struct lb_memory *mem,
+ uint32_t type, unsigned long startk, unsigned long endk)
+{
+ int entries;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+ mem->map[entries].start = startk;
+ mem->map[entries].start <<= 10;
+ mem->map[entries].size = endk - startk;
+ mem->map[entries].size <<= 10;
+ mem->map[entries].type = type;
+ mem->size += sizeof(mem->map[0]);
+}
+
+static void lb_reserve_table_memory(struct lb_header *head)
+{
+ struct lb_record *last_rec;
+ struct lb_memory *mem;
+ uint64_t start;
+ uint64_t end;
+ int i, entries;
+
+ last_rec = lb_last_record(head);
+ mem = get_lb_mem();
+ start = (unsigned long)head;
+ end = (unsigned long)last_rec;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+ /* Resize the right two memory areas so this table is in
+ * a reserved area of memory. Everything has been carefully
+ * setup so that is all we need to do.
+ */
+ for(i = 0; i < entries; i++ ) {
+ uint64_t map_start = mem->map[i].start;
+ uint64_t map_end = map_start + mem->map[i].size;
+ /* Does this area need to be expanded? */
+ if (map_end == start) {
+ mem->map[i].size = end - map_start;
+ }
+ /* Does this area need to be contracted? */
+ else if (map_start == start) {
+ mem->map[i].start = end;
+ mem->map[i].size = map_end - end;
+ }
+ }
+}
+
+
+unsigned long lb_table_fini(struct lb_header *head)
+{
+ struct lb_record *rec, *first_rec;
+ rec = lb_last_record(head);
+ if (head->table_entries) {
+ head->table_bytes += rec->size;
+ }
+ lb_reserve_table_memory(head);
+ first_rec = lb_first_record(head);
+ head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes);
+ head->header_checksum = 0;
+ head->header_checksum = compute_ip_checksum(head, sizeof(*head));
+ printk_debug("Wrote linuxbios table at: %p - %p checksum %lx\n",
+ head, rec, head->table_checksum);
+ return (unsigned long)rec;
+}
+
+
+/* Routines to extract part so the linuxBIOS table or
+ * information from the linuxBIOS table after we have written it.
+ * Currently get_lb_mem relies on a global we can change the
+ * implementaiton.
+ */
+static struct lb_memory *mem_ranges = 0;
+struct lb_memory *get_lb_mem(void)
+{
+ return mem_ranges;
+}
+
+unsigned long write_linuxbios_table(
+ unsigned long *processor_map,
+ struct mem_range *ram,
+ unsigned long low_table_start, unsigned long low_table_end,
+ unsigned long rom_table_startk, unsigned long rom_table_endk)
+{
+ unsigned long table_size;
+ struct mem_range *ramp;
+ struct lb_header *head;
+ struct lb_memory *mem;
+#if HAVE_OPTION_TABLE == 1
+ struct lb_record *rec_dest, *rec_src;
+#endif
+
+ head = lb_table_init(low_table_end);
+ low_table_end = (unsigned long)head;
+#if HAVE_OPTION_TABLE == 1
+ /* Write the option config table... */
+ rec_dest = lb_new_record(head);
+ rec_src = (struct lb_record *)&option_table;
+ memcpy(rec_dest, rec_src, rec_src->size);
+#endif
+ mem = lb_memory(head);
+ mem_ranges = mem;
+ /* I assume there is always ram at address 0 */
+ /* Reserve our tables in low memory */
+ table_size = (low_table_end - low_table_start);
+ lb_memory_range(mem, LB_MEM_TABLE, 0, table_size);
+ lb_memory_range(mem, LB_MEM_RAM, table_size, (ram[0].sizek << 10) - table_size);
+ /* Reserving pci memory mapped space will keep the kernel from booting seeing
+ * any pci resources.
+ */
+ for(ramp = &ram[1]; ramp->sizek; ramp++) {
+ unsigned long startk, endk;
+ startk = ramp->basek;
+ endk = startk + ramp->sizek;
+ if ((startk < rom_table_startk) && (endk > rom_table_startk)) {
+ lb_memory_rangek(mem, LB_MEM_RAM, startk, rom_table_startk);
+ startk = rom_table_startk;
+ }
+ if ((startk == rom_table_startk) && (endk > startk)) {
+ unsigned long tend;
+ tend = rom_table_endk;
+ if (tend > endk) {
+ tend = endk;
+ }
+ lb_memory_rangek(mem, LB_MEM_TABLE, rom_table_startk, tend);
+ startk = tend;
+ }
+ if (endk > startk) {
+ lb_memory_rangek(mem, LB_MEM_RAM, startk, endk);
+ }
+ }
+
+ /* Record our motheboard */
+ lb_mainboard(head);
+ /* Record our various random string information */
+ lb_strings(head);
+
+ low_table_end = lb_table_fini(head);
+
+ /* Remember where my valid memory ranges are */
+ return low_table_end;
+}
diff --git a/src/arch/ppc/include/arch/boot/boot.h b/src/arch/ppc/include/arch/boot/boot.h
new file mode 100644
index 0000000000..b68455b557
--- /dev/null
+++ b/src/arch/ppc/include/arch/boot/boot.h
@@ -0,0 +1,8 @@
+#ifndef ASM_I386_BOOT_H
+#define ASM_I386_BOOT_H
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_PPC
+
+#endif /* ASM_I386_BOOT_H */
diff --git a/src/arch/ppc/include/arch/io.h b/src/arch/ppc/include/arch/io.h
new file mode 100644
index 0000000000..f51f14089e
--- /dev/null
+++ b/src/arch/ppc/include/arch/io.h
@@ -0,0 +1,192 @@
+/*
+ * BK Id: SCCS/s.io.h 1.14 10/16/01 15:58:42 trini
+ */
+#ifndef _PPC_IO_H
+#define _PPC_IO_H
+#include <types.h>
+
+#define SIO_CONFIG_RA 0x398
+#define SIO_CONFIG_RD 0x399
+
+#define SLOW_DOWN_IO
+
+#define PMAC_ISA_MEM_BASE 0
+#define PMAC_PCI_DRAM_OFFSET 0
+#define CHRP_ISA_IO_BASE 0xf8000000
+#define CHRP_ISA_MEM_BASE 0xf7000000
+#define CHRP_PCI_DRAM_OFFSET 0
+#define PREP_ISA_IO_BASE 0x80000000
+#define PREP_ISA_MEM_BASE 0xc0000000
+#define PREP_PCI_DRAM_OFFSET 0x80000000
+
+#define _IO_BASE 0xfe000000
+
+#define readb(addr) in_8((volatile u8 *)(addr))
+#define writeb(b,addr) out_8((volatile u8 *)(addr), (b))
+#define readw(addr) in_le16((volatile u16 *)(addr))
+#define readl(addr) in_le32((volatile u32 *)(addr))
+#define writew(b,addr) out_le16((volatile u16 *)(addr),(b))
+#define writel(b,addr) out_le32((volatile u32 *)(addr),(b))
+
+
+#define __raw_readb(addr) (*(volatile unsigned char *)(addr))
+#define __raw_readw(addr) (*(volatile unsigned short *)(addr))
+#define __raw_readl(addr) (*(volatile unsigned int *)(addr))
+#define __raw_writeb(v, addr) (*(volatile unsigned char *)(addr) = (v))
+#define __raw_writew(v, addr) (*(volatile unsigned short *)(addr) = (v))
+#define __raw_writel(v, addr) (*(volatile unsigned int *)(addr) = (v))
+
+/*
+ * The insw/outsw/insl/outsl macros don't do byte-swapping.
+ * They are only used in practice for transferring buffers which
+ * are arrays of bytes, and byte-swapping is not appropriate in
+ * that case. - paulus
+ */
+#define insb(port, buf, ns) _insb((u8 *)((port)+_IO_BASE), (buf), (ns))
+#define outsb(port, buf, ns) _outsb((u8 *)((port)+_IO_BASE), (buf), (ns))
+#define insw(port, buf, ns) _insw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define outsw(port, buf, ns) _outsw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define insl(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
+#define outsl(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
+
+#define inb(port) in_8((u8 *)((port)+_IO_BASE))
+#define outb(val, port) out_8((u8 *)((port)+_IO_BASE), (val))
+#define inw(port) in_le16((u16 *)((port)+_IO_BASE))
+#define outw(val, port) out_le16((u16 *)((port)+_IO_BASE), (val))
+#define inl(port) in_le32((u32 *)((port)+_IO_BASE))
+#define outl(val, port) out_le32((u32 *)((port)+_IO_BASE), (val))
+
+#define inb_p(port) inb((port))
+#define outb_p(val, port) outb((val), (port))
+#define inw_p(port) inw((port))
+#define outw_p(val, port) outw((val), (port))
+#define inl_p(port) inl((port))
+#define outl_p(val, port) outl((val), (port))
+
+extern void _insb(volatile u8 *port, void *buf, int ns);
+extern void _outsb(volatile u8 *port, const void *buf, int ns);
+extern void _insw(volatile u16 *port, void *buf, int ns);
+extern void _outsw(volatile u16 *port, const void *buf, int ns);
+extern void _insl(volatile u32 *port, void *buf, int nl);
+extern void _outsl(volatile u32 *port, const void *buf, int nl);
+extern void _insw_ns(volatile u16 *port, void *buf, int ns);
+extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
+extern void _insl_ns(volatile u32 *port, void *buf, int nl);
+extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
+
+/*
+ * The *_ns versions below don't do byte-swapping.
+ * Neither do the standard versions now, these are just here
+ * for older code.
+ */
+#define insw_ns(port, buf, ns) _insw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define outsw_ns(port, buf, ns) _outsw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define insl_ns(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
+#define outsl_ns(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
+
+
+#define IO_SPACE_LIMIT ~0
+
+#define memset_io(a,b,c) memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
+
+/*
+ * Enforce In-order Execution of I/O:
+ * Acts as a barrier to ensure all previous I/O accesses have
+ * completed before any further ones are issued.
+ */
+extern inline void eieio(void)
+{
+ __asm__ __volatile__ ("eieio" : : : "memory");
+}
+
+/* Enforce in-order execution of data I/O.
+ * No distinction between read/write on PPC; use eieio for all three.
+ */
+#define iobarrier_rw() eieio()
+#define iobarrier_r() eieio()
+#define iobarrier_w() eieio()
+
+/*
+ * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ */
+extern inline int in_8(volatile unsigned char *addr)
+{
+ int ret;
+
+ __asm__ __volatile__("lbz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
+ return ret;
+}
+
+extern inline void out_8(volatile unsigned char *addr, int val)
+{
+ __asm__ __volatile__("stb%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
+}
+
+extern inline int in_le16(volatile unsigned short *addr)
+{
+ int ret;
+
+ __asm__ __volatile__("lhbrx %0,0,%1; eieio" : "=r" (ret) :
+ "r" (addr), "m" (*addr));
+ return ret;
+}
+
+extern inline int in_be16(volatile unsigned short *addr)
+{
+ int ret;
+
+ __asm__ __volatile__("lhz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
+ return ret;
+}
+
+extern inline void out_le16(volatile unsigned short *addr, int val)
+{
+ __asm__ __volatile__("sthbrx %1,0,%2; eieio" : "=m" (*addr) :
+ "r" (val), "r" (addr));
+}
+
+extern inline void out_be16(volatile unsigned short *addr, int val)
+{
+ __asm__ __volatile__("sth%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
+}
+
+extern inline unsigned in_le32(volatile unsigned *addr)
+{
+ unsigned ret;
+
+ __asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) :
+ "r" (addr), "m" (*addr));
+ return ret;
+}
+
+extern inline unsigned in_be32(volatile unsigned *addr)
+{
+ unsigned ret;
+
+ __asm__ __volatile__("lwz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
+ return ret;
+}
+
+extern inline void out_le32(volatile unsigned *addr, int val)
+{
+ __asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
+ "r" (val), "r" (addr));
+}
+
+extern inline void out_be32(volatile unsigned *addr, int val)
+{
+ __asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
+}
+
+extern inline void _insw_ns(volatile u16 *port, void *buf, int ns)
+{
+ u16 * b = (u16 *)buf;
+
+ while (ns > 0) {
+ *b++ = readw(port);
+ ns--;
+ }
+}
+#endif
diff --git a/src/arch/ppc/include/arch/pirq_routing.h b/src/arch/ppc/include/arch/pirq_routing.h
new file mode 100644
index 0000000000..dad8531eb5
--- /dev/null
+++ b/src/arch/ppc/include/arch/pirq_routing.h
@@ -0,0 +1,54 @@
+#ifndef ARCH_PIRQ_ROUTING_H
+#define ARCH_PIRQ_ROUTING_H
+
+#include <types.h>
+
+#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
+#define PIRQ_VERSION 0x0100
+
+struct irq_info {
+ u8 bus, devfn; /* Bus, device and function */
+ struct {
+ u8 link; /* IRQ line ID, chipset dependent, 0=not routed */
+ u16 bitmap; /* Available IRQs */
+ } __attribute__((packed)) irq[4];
+ u8 slot; /* Slot number, 0=onboard */
+ u8 rfu;
+} __attribute__((packed));
+
+#if defined(IRQ_SLOT_COUNT)
+#define IRQ_SLOTS_COUNT IRQ_SLOT_COUNT
+#elif (__GNUC__ < 3)
+#define IRQ_SLOTS_COUNT 1
+#else
+#define IRQ_SLOTS_COUNT
+#endif
+
+struct irq_routing_table {
+ u32 signature; /* PIRQ_SIGNATURE should be here */
+ u16 version; /* PIRQ_VERSION */
+ u16 size; /* Table size in bytes */
+ u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */
+ u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
+ u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */
+ u32 miniport_data; /* Crap */
+ u8 rfu[11];
+ u8 checksum; /* Modulo 256 checksum must give zero */
+ struct irq_info slots[IRQ_SLOTS_COUNT];
+} __attribute__((packed));
+
+extern const struct irq_routing_table intel_irq_routing_table;
+
+#if defined(DEBUG) && defined(HAVE_PIRQ_TABLE)
+void check_pirq_routing_table(void);
+#else
+#define check_pirq_routing_table() do {} while(0)
+#endif
+
+#if defined(HAVE_PIRQ_TABLE)
+unsigned long copy_pirq_routing_table(unsigned long start);
+#else
+#define copy_pirq_routing_table(start) (start)
+#endif
+
+#endif /* ARCH_PIRQ_ROUTING_H */
diff --git a/src/arch/ppc/include/bitops.h b/src/arch/ppc/include/bitops.h
new file mode 100644
index 0000000000..23cfa66077
--- /dev/null
+++ b/src/arch/ppc/include/bitops.h
@@ -0,0 +1,22 @@
+#ifndef I386_BITOPS_H
+#define I386_BITOPS_H
+
+/**
+ * log2 - Find the truncated log base 2 of x
+ */
+
+static inline unsigned long log2(unsigned long x)
+{
+ unsigned long r = 0;
+ /*
+ __asm__(
+ "bsrl %1, %0\n\t"
+ "jnz 1f\n\t"
+ "movl $-1, %0\n\t"
+ "1:\n\t"
+ : "=r" (r) : "r" (x));
+ */
+ return r;
+
+}
+#endif /* I386_BITOPS_H */
diff --git a/src/arch/ppc/include/ppc.h b/src/arch/ppc/include/ppc.h
new file mode 100644
index 0000000000..fe4aa1654b
--- /dev/null
+++ b/src/arch/ppc/include/ppc.h
@@ -0,0 +1,21 @@
+/* $Id$ */
+/* Copyright 2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+#ifndef _PPC_H
+#define _PPC_H
+
+#define BIG_ENDIAN
+#define RODATA __attribute__ ((__section__ (".rodata")))
+
+/* Do CPU specific setup, with optional icache */
+void ppc_setup_cpu(int icache);
+
+void ppc_enable_dcache(void);
+void ppc_disable_dcache(void);
+void ppc_enable_mmu(void);
+
+/* Describe which sort of ppc CPU I am */
+void ppc_identify(void);
+
+#endif
diff --git a/src/arch/ppc/include/ppc_asm.tmpl b/src/arch/ppc/include/ppc_asm.tmpl
new file mode 100644
index 0000000000..da1f7f7782
--- /dev/null
+++ b/src/arch/ppc/include/ppc_asm.tmpl
@@ -0,0 +1,293 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file contains all the macros and symbols which define
+ * a PowerPC assembly language environment.
+ */
+#ifndef __PPC_ASM_TMPL__
+#define __PPC_ASM_TMPL__
+
+/***************************************************************************
+ *
+ * These definitions simplify the ugly declarations necessary for GOT
+ * definitions.
+ *
+ * Stolen from prepboot/bootldr.h, (C) 1998 Gabriel Paubert, paubert@iram.es
+ *
+ * Uses r14 to access the GOT
+ */
+
+#define START_GOT \
+ .section ".got2","aw"; \
+.LCTOC1 = .+32768
+
+#define END_GOT \
+ .text
+
+#define GET_GOT \
+ bl 1f ; \
+ .text 2 ; \
+0: .long .LCTOC1-1f ; \
+ .text ; \
+1: mflr r14 ; \
+ lwz r0,0b-1b(r14) ; \
+ add r14,r0,r14 ;
+
+#define GOT_ENTRY(NAME) .L_ ## NAME = . - .LCTOC1 ; .long NAME
+
+#define GOT(NAME) .L_ ## NAME (r14)
+
+
+/***************************************************************************
+ * Register names
+ */
+#define r0 0
+#define r1 1
+#define r2 2
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+#define r9 9
+#define r10 10
+#define r11 11
+#define r12 12
+#define r13 13
+#define r14 14
+#define r15 15
+#define r16 16
+#define r17 17
+#define r18 18
+#define r19 19
+#define r20 20
+#define r21 21
+#define r22 22
+#define r23 23
+#define r24 24
+#define r25 25
+#define r26 26
+#define r27 27
+#define r28 28
+#define r29 29
+#define r30 30
+#define r31 31
+
+/*
+ * FP register names
+ */
+#define fr0 0
+#define fr1 1
+#define fr2 2
+#define fr3 3
+#define fr4 4
+#define fr5 5
+#define fr6 6
+#define fr7 7
+#define fr8 8
+#define fr9 9
+#define fr10 10
+#define fr11 11
+#define fr12 12
+#define fr13 13
+#define fr14 14
+#define fr15 15
+#define fr16 16
+#define fr17 17
+#define fr18 18
+#define fr19 19
+#define fr20 20
+#define fr21 21
+#define fr22 22
+#define fr23 23
+#define fr24 24
+#define fr25 25
+#define fr26 26
+#define fr27 27
+#define fr28 28
+#define fr29 29
+#define fr30 30
+#define fr31 31
+
+/* Some special registers */
+
+#define TBRU 269 /* Time base Upper/Lower (Reading) */
+#define TBRL 268
+#define TBWU 284 /* Time base Upper/Lower (Writing) */
+#define TBWL 285
+#define XER 1
+#define LR 8
+#define CTR 9
+#define HID0 1008 /* Hardware Implementation */
+#define PVR 287 /* Processor Version */
+#define SDR1 25 /* MMU hash base register */
+#define DAR 19 /* Data Address Register */
+#define SPR0 272 /* Supervisor Private Registers */
+#define SPRG0 272
+#define SPR1 273
+#define SPRG1 273
+#define SPR2 274
+#define SPRG2 274
+#define SPR3 275
+#define SPRG3 275
+#define DSISR 18
+#define SRR0 26 /* Saved Registers (exception) */
+#define SRR1 27
+#define DEC 22 /* Decrementer */
+#define EAR 282 /* External Address Register */
+#define ICR 148 /* Interrupt Cause Register (37-44) */
+#define DER 149
+#define COUNTA 150 /* Breakpoint Counter (37-44) */
+#define COUNTB 151 /* Breakpoint Counter (37-44) */
+#define LCTRL1 156 /* Load/Store Support (37-40) */
+#define LCTRL2 157 /* Load/Store Support (37-41) */
+#define ICTRL 158
+
+/* Registers in the processor's internal memory map that we use.
+*/
+#define IMMR 0xff000000
+
+#define SYPCR 0x00000004
+#define BR0 0x00000100
+#define OR0 0x00000104
+#define BR1 0x00000108
+#define OR1 0x0000010c
+#define BR2 0x00000110
+#define OR2 0x00000114
+#define BR3 0x00000118
+#define OR3 0x0000011c
+#define BR4 0x00000120
+#define OR4 0x00000124
+
+#define MAR 0x00000164
+#define MCR 0x00000168
+#define MAMR 0x00000170
+#define MBMR 0x00000174
+#define MSTAT 0x00000178
+#define MPTPR 0x0000017a
+#define MDR 0x0000017c
+
+#define TBSCR 0x00000200
+#define TBREFF0 0x00000204
+
+#define PLPRCR 0x00000284
+
+#define curptr r2
+
+#define SYNC \
+ sync; \
+ isync
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't. To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
+ */
+#define STACK_UNDERHEAD 64
+
+#if 0 /* we don't use virtual addresses in PPCBOOT */
+#define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h
+#define tovirt(rd,rs,rt) addis rd,rs,KERNELBASE@h
+#else
+#define tophys(rd,rs,rt) mr rd,rs
+#define tovirt(rd,rs,rt) mr rd,rs
+#endif
+
+/*
+ * Exception entry code. This code runs with address translation
+ * turned off, i.e. using physical addresses.
+ * We assume sprg3 has the physical address of the current
+ * task's thread_struct.
+ */
+#define EXCEPTION_PROLOG \
+ mtspr SPRG0,r20; \
+ mtspr SPRG1,r21; \
+ mfcr r20; \
+ tophys(r21,r1,r21); /* use tophys(kernel sp) otherwise */ \
+ subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\
+1: stw r20,_CCR(r21); /* save registers */ \
+ stw r22,GPR22(r21); \
+ stw r23,GPR23(r21); \
+ mfspr r20,SPRG0; \
+ stw r20,GPR20(r21); \
+ mfspr r22,SPRG1; \
+ stw r22,GPR21(r21); \
+ mflr r20; \
+ stw r20,_LINK(r21); \
+ mfctr r22; \
+ stw r22,_CTR(r21); \
+ mfspr r20,XER; \
+ stw r20,_XER(r21); \
+ mfspr r22,SRR0; \
+ mfspr r23,SRR1; \
+ stw r0,GPR0(r21); \
+ stw r1,GPR1(r21); \
+ stw r2,GPR2(r21); \
+ stw r1,0(r21); \
+ tovirt(r1,r21,r1); /* set new kernel sp */ \
+ SAVE_4GPRS(3, r21);
+/*
+ * Note: code which follows this uses cr0.eq (set if from kernel),
+ * r21, r22 (SRR0), and r23 (SRR1).
+ */
+
+/*
+ * Exception vectors.
+ *
+ * The data words for `hdlr' and `int_return' are initialized with
+ * OFFSET values only; they must be relocated first before they can
+ * be used!
+ */
+#define STD_EXCEPTION(n, label, hdlr) \
+ . = n; \
+label: \
+ EXCEPTION_PROLOG; \
+ lwz r3,GOT(transfer_to_handler); \
+ mtlr r3; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ li r20,MSR_KERNEL; \
+ blrl ; \
+.L_ ## label : \
+ .long hdlr - _start + EXC_OFF_SYS_RESET; \
+ .long int_return - _start + EXC_OFF_SYS_RESET
+
+
+#endif /* __PPC_ASM_TMPL__ */
diff --git a/src/arch/ppc/include/ppcreg.h b/src/arch/ppc/include/ppcreg.h
new file mode 100644
index 0000000000..5ec0dd9417
--- /dev/null
+++ b/src/arch/ppc/include/ppcreg.h
@@ -0,0 +1,128 @@
+/* $Id$ */
+/* Copyright 2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+/* In the MSR, not all bits are interesting to us
+ 13 - POW - Power management
+ 14 - TGPR - temporary registers for page table routines
+ 15 - ILE - Exception little endian
+ 16 - EE - External interrupts
+ 17 - PR - Privilege level
+ 18 - FP - Floating Point available
+ 19 - ME - Machine check exception enable
+ 20 - FE0 - Floating exception mode 0
+ 21 - SE - Single step trace mode
+ 22 - BE - Branch trace enable
+ 23 - FE1 - Floating exception mode 1
+ 25 - IP - Exception prefix
+ 26 - IR - Instruction address translation
+ 27 - DR - Data address translation
+ 30 - RI - Recoverable exception
+ 31 - LE - Little endian mode
+ MSR_MASK is the bits we do not change.
+ */
+
+#define MSR_MASK 0xfff8008c
+#define MSR_POW 0x00040000
+#define MSR_TGPR 0x00020000
+#define MSR_ILE 0x00010000
+#define MSR_EE 0x00008000
+#define MSR_PR 0x00004000
+#define MSR_FP 0x00002000
+#define MSR_ME 0x00001000
+#define MSR_FE0 0x00000800
+#define MSR_SE 0x00000400
+#define MSR_BE 0x00000200
+#define MSR_FE1 0x00000100
+#define MSR_IP 0x00000040
+#define MSR_IR 0x00000020
+#define MSR_DR 0x00000010
+#define MSR_RI 0x00000002
+#define MSR_LE 0x00000001
+
+#define MSR_DEFAULT (MSR_FP | MSR_IR | MSR_DR)
+
+/* We are interested in the following hid0 bits:
+ 6 - ECLK - Enable external test clock (603 only)
+ 11 - DPM - Turn on dynamic power management (603 only)
+ 15 - NHR - Not hard reset
+ 16 - ICE - Instruction cache enable
+ 17 - DCE - Data cache enable
+ 18 - ILOCK - Instruction cache lock
+ 19 - DLOCK - Data cache lock
+ 20 - ICFI - Instruction cache invalidate
+ 21 - DCFI - Data cache invalidate
+ 24 - NOSER - Serial execution disable (604 only - turbo mode)
+ 24 - SGE - Store gathering enable (7410 only)
+ 29 - BHT - Branch history table (604 only)
+
+ I made up the tags for the 604 specific bits, as they aren't
+ named in the 604 book. The 603 book calls the invalidate bits
+ ICFI and DCI, and I have no idea why it isn't DCFI. Maybe IBM named
+ one, and Motorola named the other. */
+
+#define HID0_ECLK 0x02000000
+#define HID0_DPM 0x00100000
+#define HID0_NHR 0x00010000
+#define HID0_ICE 0x00008000
+#define HID0_DCE 0x00004000
+#define HID0_ILOCK 0x00002000
+#define HID0_DLOCK 0x00001000
+#define HID0_ICFI 0x00000800
+#define HID0_DCFI 0x00000400
+#define HID0_NOSER 0x00000080
+#define HID0_SGE 0x00000080
+#define HID0_BTIC 0x00000020
+#define HID0_BHT 0x00000004
+
+/*
+ * BAT defines
+ */
+
+/*
+ * BL field in upper BAT register
+ */
+#define BAT_BL_128K 0x00000000
+#define BAT_BL_256K 0x00000004
+#define BAT_BL_512K 0x0000000C
+#define BAT_BL_1M 0x0000001C
+#define BAT_BL_2M 0x0000003C
+#define BAT_BL_4M 0x0000007C
+#define BAT_BL_8M 0x000000FC
+#define BAT_BL_16M 0x000001FC
+#define BAT_BL_32M 0x000003FC
+#define BAT_BL_64M 0x000007FC
+#define BAT_BL_128M 0x00000FFC
+#define BAT_BL_256M 0x00001FFC
+
+/*
+ * Supervisor/user valid mode in upper BAT register
+ */
+#define BAT_VALID_SUPERVISOR 0x00000002
+#define BAT_VALID_USER 0x00000001
+#define BAT_INVALID 0x00000000
+
+/*
+ * WIMG bit setting in lower BAT register
+ */
+#define BAT_WRITE_THROUGH 0x00000040
+#define BAT_CACHE_INHIBITED 0x00000020
+#define BAT_COHERENT 0x00000010
+#define BAT_GUARDED 0x00000008
+
+/*
+ * Protection bits in lower BAT register
+ */
+#define BAT_NO_ACCESS 0x00000000
+#define BAT_READ_ONLY 0x00000001
+#define BAT_READ_WRITE 0x00000002
+
+#ifndef ASM
+unsigned __getmsr(void);
+void __setmsr(unsigned value);
+unsigned __gethid0(void);
+unsigned __gethid1(void);
+void __sethid0(unsigned value);
+unsigned __getpvr(void);
+#endif
+
diff --git a/src/arch/ppc/include/stddef.h b/src/arch/ppc/include/stddef.h
new file mode 100644
index 0000000000..2ea8ebb13c
--- /dev/null
+++ b/src/arch/ppc/include/stddef.h
@@ -0,0 +1,15 @@
+#ifndef PPC_STDDEF_H
+#define PPC_STDDEF_H
+
+typedef long ptrdiff_t;
+typedef unsigned long size_t;
+typedef long ssize_t;
+
+typedef int wchar_t;
+typedef unsigned int wint_t;
+
+#define NULL 0
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* PPC_STDDEF_H */
diff --git a/src/arch/ppc/include/stdint.h b/src/arch/ppc/include/stdint.h
new file mode 100644
index 0000000000..73da924b1e
--- /dev/null
+++ b/src/arch/ppc/include/stdint.h
@@ -0,0 +1,52 @@
+#ifndef PPC_STDINT_H
+#define PPC_STDINT_H
+
+/* Exact integral types */
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+
+/* Small types */
+typedef unsigned char uint_least8_t;
+typedef signed char int_least8_t;
+
+typedef unsigned short uint_least16_t;
+typedef signed short int_least16_t;
+
+typedef unsigned int uint_least32_t;
+typedef signed int int_least32_t;
+
+typedef unsigned long long uint_least64_t;
+typedef signed long long int_least64_t;
+
+/* Fast Types */
+typedef unsigned char uint_fast8_t;
+typedef signed char int_fast8_t;
+
+typedef unsigned int uint_fast16_t;
+typedef signed int int_fast16_t;
+
+typedef unsigned int uint_fast32_t;
+typedef signed int int_fast32_t;
+
+typedef unsigned long long uint_fast64_t;
+typedef signed long long int_fast64_t;
+
+/* Types for `void *' pointers. */
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+/* Largest integral types */
+typedef long long int intmax_t;
+typedef unsigned long long uintmax_t;
+
+
+#endif /* PPC_STDINT_H */
diff --git a/src/arch/ppc/include/timer.h b/src/arch/ppc/include/timer.h
new file mode 100644
index 0000000000..9a2328f7cd
--- /dev/null
+++ b/src/arch/ppc/include/timer.h
@@ -0,0 +1,13 @@
+/* $Id$ */
+/* Copyright 2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+#ifndef _TIMER_H
+#define __TIMER_H
+
+unsigned get_hz(void);
+unsigned ticks_since_boot(void);
+void sleep_ticks(unsigned);
+void udelay(int);
+
+#endif
diff --git a/src/arch/ppc/lib/c_start.S b/src/arch/ppc/lib/c_start.S
new file mode 100644
index 0000000000..1719fd7103
--- /dev/null
+++ b/src/arch/ppc/lib/c_start.S
@@ -0,0 +1,109 @@
+/* $Id$ */
+/* Copyright 2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+/*
+ * The assumption is that we're located in ROM and we have a fake stack
+ * located in cache. Our task is to turn on memory proper, the finish
+ * configuring the machine.
+ */
+
+#define ASM
+#include "ppcreg.h"
+#include <ppc_asm.tmpl>
+
+.section ".text"
+.globl _start
+
+_start:
+ /*
+ * init stack pointer to real ram now that memory is on
+ */
+ lis r1, _estack@ha
+ addi r1, r1, _estack@l
+ stwu r0,-64(r1)
+ stwu r1,-24(r1)
+
+ /*
+ * Clear stack
+ */
+ lis r4, _stack@ha
+ addi r4, r4, _stack@l
+ lis r7, _estack@ha
+ addi r7, r7, _estack@l
+ lis r5, 0
+1: stwx r5, 0, r4
+ addi r4, r4, 4
+ cmp 0, 0, r4, r7
+ ble 1b
+ sync
+
+ /*
+ * Clear bss
+ */
+ lis r4, _bss@ha
+ addi r4, r4, _bss@l
+ lis r7, _ebss@ha
+ addi r7, r7, _ebss@l
+ lis r5, 0
+1: stwx r5, 0, r4
+ addi r4, r4, 4
+ cmp 0, 0, r4, r7
+ ble 1b
+ sync
+
+ /*
+ * Set up the EABI pointers, before we enter any C code
+ */
+ lis r13, _SDA_BASE_@ha
+ addi r13, r13, _SDA_BASE_@l
+ lis r2, _SDA2_BASE_@ha
+ addi r2, r2, _SDA2_BASE_@l
+
+ /*
+ * load start address into SRR0 for rfi
+ */
+ lis r3, hardwaremain@ha
+ addi r3, r3, hardwaremain@l
+ mtspr SRR0, r3
+
+ /*
+ * load the current MSR into SRR1 so that it will be copied
+ * back into MSR on rfi
+ */
+ mfmsr r4
+ mtspr SRR1, r4 // load SRR1 with r4
+
+ /*
+ * If something returns after rfi then die
+ */
+ lis r3, dead@ha
+ addi r3, r3, dead@l
+ mtlr r3
+
+ /*
+ * Complete rest of initialization in C (hardwaremain)
+ */
+ rfi
+
+ /*
+ * Stop here if something goes wrong
+ */
+dead:
+ b dead
+ /*NOTREACHED*/
+
+/* Remove need for ecrti.o and ectrn.o */
+.globl __init
+__init:
+.globl __fini
+__fini:
+.globl __CTOR_LIST__
+__CTOR_LIST__:
+.globl __CTOR_END__
+__CTOR_END__:
+.globl __DTOR_LIST__
+__DTOR_LIST__:
+.globl __DTOR_END__
+__DTOR_END__:
+ blr
diff --git a/src/arch/ppc/lib/floats.S b/src/arch/ppc/lib/floats.S
new file mode 100644
index 0000000000..57b38cb9c3
--- /dev/null
+++ b/src/arch/ppc/lib/floats.S
@@ -0,0 +1,45 @@
+/* $Id$ */
+/* Copyright 1999-2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+#include <ppc_asm.tmpl>
+
+ .globl _init_float_registers
+
+_init_float_registers:
+ lfd fr0, 0(r3)
+ lfd fr1, 0(r3)
+ lfd fr2, 0(r3)
+ lfd fr3, 0(r3)
+ lfd fr4, 0(r3)
+ lfd fr5, 0(r3)
+ lfd fr6, 0(r3)
+ lfd fr7, 0(r3)
+ lfd fr8, 0(r3)
+ lfd fr9, 0(r3)
+ lfd fr10, 0(r3)
+ lfd fr11, 0(r3)
+ lfd fr12, 0(r3)
+ lfd fr13, 0(r3)
+ lfd fr14, 0(r3)
+ lfd fr15, 0(r3)
+ lfd fr16, 0(r3)
+ lfd fr17, 0(r3)
+ lfd fr18, 0(r3)
+ lfd fr19, 0(r3)
+ lfd fr20, 0(r3)
+ lfd fr21, 0(r3)
+ lfd fr22, 0(r3)
+ lfd fr23, 0(r3)
+ lfd fr24, 0(r3)
+ lfd fr25, 0(r3)
+ lfd fr26, 0(r3)
+ lfd fr27, 0(r3)
+ lfd fr28, 0(r3)
+ lfd fr29, 0(r3)
+ lfd fr30, 0(r3)
+ lfd fr31, 0(r3)
+ blr
+
+ .end
+
diff --git a/src/arch/ppc/lib/floats.inc b/src/arch/ppc/lib/floats.inc
new file mode 100644
index 0000000000..5c366af63f
--- /dev/null
+++ b/src/arch/ppc/lib/floats.inc
@@ -0,0 +1,43 @@
+/* $Id$ */
+/* Copyright 1999-2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+/* .text*/
+ .globl _init_float_registers
+
+_init_float_registers:
+ lfd 0, 0(3)
+ lfd 1, 0(3)
+ lfd 2, 0(3)
+ lfd 3, 0(3)
+ lfd 4, 0(3)
+ lfd 5, 0(3)
+ lfd 6, 0(3)
+ lfd 7, 0(3)
+ lfd 8, 0(3)
+ lfd 9, 0(3)
+ lfd 10, 0(3)
+ lfd 11, 0(3)
+ lfd 12, 0(3)
+ lfd 13, 0(3)
+ lfd 14, 0(3)
+ lfd 15, 0(3)
+ lfd 16, 0(3)
+ lfd 17, 0(3)
+ lfd 18, 0(3)
+ lfd 19, 0(3)
+ lfd 20, 0(3)
+ lfd 21, 0(3)
+ lfd 22, 0(3)
+ lfd 23, 0(3)
+ lfd 24, 0(3)
+ lfd 25, 0(3)
+ lfd 26, 0(3)
+ lfd 27, 0(3)
+ lfd 28, 0(3)
+ lfd 29, 0(3)
+ lfd 30, 0(3)
+ lfd 31, 0(3)
+ blr
+ .end
+
diff --git a/src/arch/ppc/lib/setup.c b/src/arch/ppc/lib/setup.c
new file mode 100644
index 0000000000..000a4b15a9
--- /dev/null
+++ b/src/arch/ppc/lib/setup.c
@@ -0,0 +1,130 @@
+/* $Id$ */
+/* Copyright 2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+#include "ppc.h"
+#include "ppcreg.h"
+
+unsigned __getmsr(void)
+{
+ unsigned result;
+ __asm__ volatile ("mfmsr %0" : "=r" (result));
+ return result;
+}
+
+unsigned __gethid0(void)
+{
+ unsigned result;
+ __asm__ volatile ("mfspr %0,1008" : "=r" (result));
+ return result;
+}
+
+unsigned __gethid1(void)
+{
+ unsigned result;
+ __asm__ volatile ("mfspr %0,1009" : "=r" (result));
+ return result;
+}
+
+void __sethid0(unsigned value)
+{
+ __asm__ volatile ("mtspr 1008,%0" : : "r" (value));
+}
+
+unsigned __getpvr(void)
+{
+ int result;
+ __asm__("mfspr %0, 287" : "=r" (result));
+ return result;
+}
+
+void __setmsr(unsigned value)
+{
+ __asm__ volatile ("mtmsr %0; sync" :: "r" (value));
+}
+
+void __set1015(unsigned value)
+{
+ __asm__ volatile ("mtspr 1015,%0" : : "r" (value));
+}
+
+extern void _init_float_registers(const double *);
+/*RODATA static const double dummy_float = 1.0;*/
+static const double dummy_float = 1.0;
+
+#define HID0_DCACHE HID0_DCE
+#define MSR_DATA MSR_DR
+
+void ppc_setup_cpu(int icache)
+{
+ int type = __getpvr() >> 16;
+ int version = __getpvr() & 0xffff;
+
+ if (type == 0xc)
+ {
+ if (version == 0x0200)
+ __set1015(0x19000004);
+ else if (((version & 0xff00) == 0x0200) &&
+ (version != 0x0209))
+ __set1015(0x01000000);
+ }
+ if (icache)
+ {
+ __sethid0(HID0_NHR | HID0_BHT | HID0_ICE | HID0_ICFI | HID0_BTIC
+ | HID0_DCACHE);
+ __sethid0(HID0_DPM | HID0_NHR | HID0_BHT | HID0_ICE | HID0_BTIC
+ | HID0_DCACHE);
+ }
+ else
+ {
+ __sethid0(HID0_DPM | HID0_NHR | HID0_BHT | HID0_BTIC | HID0_DCACHE);
+ }
+#if 1
+ /* if (type == 8 || type == 12) */
+ {
+ __setmsr(MSR_FP | MSR_DATA);
+ _init_float_registers(&dummy_float);
+ }
+#endif
+}
+
+void ppc_enable_dcache(void)
+{
+ /*
+ * Already enabled in crt0.S
+ */
+#if 0
+ unsigned hid0 = __gethid0();
+ __sethid0(hid0 | HID0_DCFI | HID0_DCE);
+ __sethid0(hid0 | HID0_DCE);
+#endif
+}
+
+void ppc_disable_dcache(void)
+{
+ unsigned hid0 = __gethid0();
+ __sethid0(hid0 & ~HID0_DCE);
+}
+
+void ppc_enable_mmu(void)
+{
+ unsigned msr = __getmsr();
+ __setmsr(msr | MSR_DR | MSR_IR);
+}
+
+void make_coherent(void *base, unsigned length)
+{
+ unsigned hid0 = __gethid0();
+
+ if (hid0 & HID0_DCE)
+ {
+ unsigned i;
+ unsigned offset = 0x1f & (unsigned) base;
+ unsigned adjusted_base = (unsigned) base & ~0x1f;
+ for(i = 0; i < length + offset; i+= 32)
+ __asm__ volatile ("dcbf %1,%0" : : "r" (adjusted_base), "r" (i));
+ if (hid0 & HID0_ICE)
+ for(i = 0; i < length + offset; i+= 32)
+ __asm__ volatile ("icbi %1,%0" : : "r" (adjusted_base), "r" (i));
+ }
+}
diff --git a/src/arch/ppc/lib/timebase.S b/src/arch/ppc/lib/timebase.S
new file mode 100644
index 0000000000..48171db498
--- /dev/null
+++ b/src/arch/ppc/lib/timebase.S
@@ -0,0 +1,13 @@
+/* $Id$ */
+/* Copyright 1999-2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+ .text
+ .globl _timebase
+_timebase:
+ mftbu 3
+ mftb 4
+ mftbu 5
+ cmpw 3, 5
+ bne _timebase
+ blr
diff --git a/src/arch/ppc/lib/timer.c b/src/arch/ppc/lib/timer.c
new file mode 100644
index 0000000000..8f968f1a5f
--- /dev/null
+++ b/src/arch/ppc/lib/timer.c
@@ -0,0 +1,31 @@
+/* $Id$ */
+/* Copyright 2000 AG Electronics Ltd. */
+/* This code is distributed without warranty under the GPL v2 (see COPYING) */
+
+#include <timer.h>
+#include <bsp.h>
+
+unsigned get_hz(void)
+{
+ return bsp_clock_speed();
+}
+
+unsigned ticks_since_boot(void)
+{
+ extern unsigned long long _timebase(void);
+ return (unsigned) (_timebase());
+}
+
+void sleep_ticks(unsigned ticks)
+{
+ unsigned then = ticks + ticks_since_boot();
+ while(ticks_since_boot() < then)
+ ;
+}
+
+void udelay(int usecs)
+{
+ unsigned ticksperusec = get_hz() / 1000000;
+
+ sleep_ticks(ticksperusec * usecs);
+}