Hi.

Some people have been asking about booting powerpc kernels on qemu.

Based on some comments about the existing rom for qemu, I looked
at OpenHackWare enough to discern how qemu started its execution
and how it gets its config.   

I then proceeded to write a wrapper patch to use as the rom and then
proceeded with a minimal platform (based on David Gibson's prep patch)
to boot a ARCH=powerpc kernel.

These patches are being posted early to allow others to use them,
they are not ready to be merged.

What works:
        -prep  (not default pmac, or core99 in later qemu)
        serial console in bootwrapper
        serial console in kernel (console=ttyS0)
        kernel must be loaded with --kernel=
                vmlinux, or vmlinuz (gzip'ed elf).
                zImage.qemu, zImage.initrd.qemu (with compiler assumptions)
        -initrd (optional)
        -append (optional)
        ide-disk and cdrom appear to work
        floppy is untested, and needs io port added.

What doesn't work:
        boot from disk
        vga (needs bios post, maybe pci)
        pci (config cycles are not working, at least on 0.6.3)

How it works:
        wrapper is compiled to run as rom
                copied from rom to ram (linked address)
                supplies initial device tree blob (because dtb = NULL)
                reads nvram for memory size, kernel, initrd, command line
        if invoked with device tree, then it only uses attached kernel
                initrd either attached or from kernel

what you need:
        2.6.23-rc3 + [ from powerpc.git for-2.6.24 branch ]
        commit 0602801c22ea1767cd0298b11da140bd5cb764d2
            [POWERPC] bootwrapper: dt_xlate_range() bugfixes
        commit a73ac50c4787b1b28d5c94bb18c60352f5dd7d6f
            [POWERPC] bootwrapper: Add dt_is_compatible()
        commit 6e913c67b3eb93e2b8bc1dc0ff854f00a760f41b
            [POWERPC] bootwrapper: Add 16-bit I/O, sync(), eieio(), and 
barrier()
        commit dc4f397d6e385c4ea0fe9732df911a86f1a78c9a
            [POWERPC] bootwrapper: serial_console_init() fixes
        commit 2f1d4899321be87bc5f0c4ee0e62c9d9ced05f80
            [POWERPC] bootwrapper: Move linker symbols into ops.h

        tell wrapper where initrd is, so it can move it if needed
                http://patchwork.ozlabs.org/linuxppc/patch?id=12168

        tell code where vmlinuz is
                http://patchwork.ozlabs.org/linuxppc/patch?id=12178

        build rom without vmlinuz
                http://patchwork.ozlabs.org/linuxppc/patch?id=12180

        Subject: Move serial_dev_init to device_initcall()
                http://patchwork.ozlabs.org/linuxppc/patch?id=13097


To run:
        build ppc_rom.bin using CONFIG_DEVICE_TREE=prep.dts with the
        dtc installed.  This will be based on zBoot.qemu and will not
        have a kernel attached.  Put this in a directory and invoke
        qemu-system-ppc -prep -L <dir-with-rom> -kernel <kernel>
        where kernel is either zImage.qemu or a (possibly compressed)
        vmlinux elf , add ide drives, -append, and -initrd as desired.

My tree has all patches in for-2.6.24 that touch arch/powerpc/boot plus
ojn's patch plus my kexec series plus the prep patch, so there will be
some rejects, especially to makefiles etc.

The first hunk to main.c to check loader_info for a command line after
the fixup callback should be a seperate patch.

The boot/Makefile has a hack to avoid ovewriting qemu.dtb.

Index: kernel/arch/powerpc/boot/main.c
===================================================================
--- kernel.orig/arch/powerpc/boot/main.c        2007-08-24 03:49:35.000000000 
-0500
+++ kernel/arch/powerpc/boot/main.c     2007-08-24 03:50:21.000000000 -0500
@@ -181,6 +181,11 @@ void start(void)
        if (platform_ops.fixups)
                platform_ops.fixups();
 
+       /* check again, in case fixups told us about it */
+       if ((loader_info.cmdline_len > 0) && (cmdline[0] == '\0'))
+               memmove(cmdline, loader_info.cmdline,
+                       min(loader_info.cmdline_len, COMMAND_LINE_SIZE-1));
+
        printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r",
               _start, get_sp());
 
Index: kernel/arch/powerpc/boot/qemu.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/qemu.c     2007-08-27 20:46:10.000000000 -0500
@@ -0,0 +1,237 @@
+/*
+ * QEMU PReP-specific stuff for the zImage boot wrapper.
+ *
+ * Copyright (C) 2007 Milton Miller, IBM Corp. <[EMAIL PROTECTED]>
+ * Copyright (C) 2006 Paul Mackerras, IBM Corp. <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License.
+ *
+ * nvram format obtained from OpenHackWare 0.4
+ * Copyright (C) 2004-2005 Jocelyn Mayer ([EMAIL PROTECTED])
+ *
+ */
+
+asm(
+/*
+ * gcc 4.1.2 seems to place this first, even with the block at the end of
+ * the file.  Put it first for good measure.  If the branch ends up at the
+ * beginning of the image then it can be started like a kernel.
+ */
+"      b       _zimage_start\n"        /* gcc 4.1.2 places this first */
+
+/*
+ * This code will be loaded by qemu as a rom at the end of memory, and
+ * execution will start at address -4.  Since the rom is read only, we
+ * and the zImage code wants to run where loaded, we must copy it to ram.
+ *
+ * move to linked place
+ * end with a branch to this code
+ * this code will be copied with dd to the end of the rom image
+ */
+
+"      .globl  copy_rom_start\n"
+"copy_rom_start:\n"
+"      bl      1f\n"
+"1:    mflr    4\n"
+"      clrrwi  4,4,19\n"               /* ROM_BITS -- get beginning of rom */
+"      lis     5,[EMAIL PROTECTED]"
+"      addi    5,5,[EMAIL PROTECTED]"
+"      lis     3,[EMAIL PROTECTED]"
+"      addi    3,3,[EMAIL PROTECTED]"
+"      subf    5,3,5\n"
+"      addi    5,5,0x1f\n"
+"      srwi    5,5,5\n"
+"      mtctr   5\n"
+"2:    lwz     24,0(4)\n"              /* copy to linked addresss */
+"      lwz     25,4(4)\n"
+"      lwz     26,8(4)\n"
+"      lwz     27,12(4)\n"
+"      lwz     28,16(4)\n"
+"      lwz     29,20(4)\n"
+"      lwz     30,24(4)\n"
+"      lwz     31,28(4)\n"
+"      stw     24,0(3)\n"
+"      stw     25,4(3)\n"
+"      stw     26,8(3)\n"
+"      stw     27,12(3)\n"
+"      stw     28,16(3)\n"
+"      stw     29,20(3)\n"
+"      stw     30,24(3)\n"
+"      stw     31,28(3)\n"
+"      dcbf    0,3\n"
+"      sync\n"
+"      icbi    0,3\n"
+"      addi    3,3,32\n"
+"      addi    4,4,32\n"
+"      bdnz    2b\n"
+"      sync\n"
+"      isync\n"
+
+       /*
+        * Put a branch to self on a few vectors in case we get an unexpected
+        * interrupt.  At least you can dump regs in the qemu monitor.
+        */
+"      lis     0,[EMAIL PROTECTED]"
+"      stw     0,0x700(0)\n"
+"      stw     0,0x300(0)\n"
+"      stw     0,0x400(0)\n"
+"      stw     0,0x900(0)\n"
+"      stw     0,0x800(0)\n"
+"      stw     0,0x200(0)\n"
+
+       /* branch to linked address */
+"      lis     0,[EMAIL PROTECTED]"
+"      ori     0,0,[EMAIL PROTECTED]"
+"      mtctr   0\n"
+"      li      3,0\n"
+"      bctrl\n"
+
+       /* must be last word before copy_rom_end */
+"      b       copy_rom_start\n"
+"      .globl  copy_rom_end\n"
+"copy_rom_end:\n"
+);
+
+
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+#include "page.h"
+#include "io.h"
+#include "gunzip_util.h"
+#include "flatdevtree.h"
+
+BSS_STACK(16*1024);
+
+unsigned char *nvram = (void *)0x80000074;     /* address of nvram on PReP */
+
+static void qemu_nvram_write(unsigned short addr, char data)
+{
+       out_8(nvram + 0, addr & 0xff);
+       out_8(nvram + 1, addr >> 8);
+       out_8(nvram + 3, data);
+}
+
+static char qemu_nvram_read(unsigned short addr)
+{
+       char data;
+       out_8(nvram + 0, addr & 0xff);
+       out_8(nvram + 1, addr >> 8);
+       data = in_8(nvram + 3);
+
+       return data;
+}
+
+static void qemu_nvram_fetch(unsigned short addr, unsigned short len, void *p)
+{
+       char *buf = p;
+       int i;
+
+       for (i = 0; i < len; i ++)
+               buf[i] = qemu_nvram_read(addr + i);     /* big endian */
+}
+
+static char arch[17];
+static void * image_start;
+static unsigned int image_len;
+
+void qemu_find_vmlinuz(struct gunzip_state *state, void **srcp,
+       unsigned long *lenp)
+{
+       *srcp = image_start;
+       *lenp = image_len;
+       gunzip_start(state, image_start, image_len);
+}
+
+/* if no device tree, read the nvram to find out about our system */
+/* based on openhackware 0.4 nvram.c get_nvram_config */
+static void qemu_fixups(void)
+{
+       char buf[32];
+       int word;
+
+       printf("qemu_fixups\n\r");
+
+       qemu_nvram_fetch(0, 16, buf);
+       printf("sig: %s", buf);
+       if (strcmp(buf, "QEMU_BIOS"))
+               fatal("no qemu sig found");
+       qemu_nvram_fetch(0x10, 16, &word);
+       if (word != 2)
+               fatal("wrong qemu nvram version");
+       /* compute crc over 0-0xfc, compare to crc in 0xfc */
+       /* size at 0x14, mult 256 0x400-0x2000 */
+       qemu_nvram_fetch(0x20, 16, buf);
+       strncpy(arch, buf, sizeof(arch)-1);
+       if (strcmp(arch,"PREP"))
+               fatal("don't understand arch %s", arch);
+
+       /* XXX: put the model in the device tree */
+
+       qemu_nvram_fetch(0x30, 16, &word);
+       printf("memory: %x\n\r", word);
+       dt_fixup_memory(0, word);
+       printf("boot device %c\n\r", qemu_nvram_read(0x34));
+       qemu_nvram_fetch(0x38, 16, &word);
+       image_start = (void *)word;
+       qemu_nvram_fetch(0x3c, 16, &word);
+       image_len = word;
+       printf("kernel %p %x\n\r", image_start, image_len);
+       qemu_nvram_fetch(0x40, 16, &word);
+       loader_info.cmdline = (void *)word;
+       qemu_nvram_fetch(0x44, 16, &word);
+       loader_info.cmdline_len = word;
+       printf("cmdline %p %x\n\r", loader_info.cmdline,
+               loader_info.cmdline_len);
+       printf("cmdline is %s\n\r", loader_info.cmdline);
+       qemu_nvram_fetch(0x48, 16, &word);
+       loader_info.initrd_addr = word;
+       qemu_nvram_fetch(0x4c, 16, &word);
+       loader_info.initrd_size = word;
+       printf("initrd %lx %lx\n\r", loader_info.initrd_addr,
+               loader_info.initrd_size);
+       /* XXX: nvram image addr at 50 */
+       /* XXX: vga width, height, depth = shorts at 54, 56, 58 */
+}
+
+/* if loaded with a device tree, then just read the tree */
+static void tree_fixups(void)
+{
+       /* get initrd from tree */
+       dt_find_initrd();
+
+       /* we must have an attached image for device-tree boot */
+}
+
+static void *heap_end; /* set in platform_init */
+
+static void *qemu_vmlinux_alloc(unsigned long size)
+{
+       if (size < (unsigned long)_start)
+               return 0;
+
+       return (void *)_ALIGN_UP((unsigned long) heap_end, 4096);
+}
+
+void platform_init(void *r3)
+{
+       struct boot_param_header *bph = r3;
+
+       heap_end = simple_alloc_init(_end, 4096*1024, 4096, 512);
+
+       if (bph)  {
+               ft_init(bph, bph->totalsize, 128);
+               platform_ops.fixups = tree_fixups;
+       } else {
+               ft_init(_dtb_start, _dtb_end - _dtb_start, 128);
+               platform_ops.fixups = qemu_fixups;
+               platform_ops.find_vmlinuz = qemu_find_vmlinuz;
+       }
+       platform_ops.vmlinux_alloc = qemu_vmlinux_alloc;
+
+       serial_console_init();
+
+       // platform_ops.vmlinux_alloc = of_vmlinux_alloc;
+}
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile      2007-08-24 05:46:36.000000000 
-0500
+++ kernel/arch/powerpc/boot/Makefile   2007-08-27 22:49:03.000000000 -0500
@@ -49,7 +49,7 @@ src-wlib := string.S crt0.S stdio.c main
                cpm-serial.c
 src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c crt0_kexec.S \
                cuboot-ebony.c treeboot-ebony.c prpmc2800.c crt0_bml.S bml.c \
-               ps3-head.S ps3-hvcall.S ps3.c prep.c \
+               ps3-head.S ps3-hvcall.S ps3.c prep.c qemu.c \
                treeboot-bamboo.c cuboot-8xx.c cuboot-pq2.c
 src-boot := $(src-wlib) $(src-plat) empty.c
 
@@ -144,6 +144,7 @@ image-$(CONFIG_PPC_HOLLY)           += zImage.hol
 image-$(CONFIG_PPC_PRPMC2800)          += zImage.prpmc2800
 image-$(CONFIG_PPC_ISERIES)            += zImage.iseries
 image-$(CONFIG_PPC_PREP)               += zImage.prep
+image-$(CONFIG_PPC_QEMU)               += zImage.qemu zBoot.qemu
 image-$(CONFIG_DEFAULT_UIMAGE)         += uImage
 image-$(CONFIG_KEXEC)                  += $(kexec-y)
 image-$(CONFIG_KEXEC)                  += $(patsubst zImage%,zBoot%,$(kexec-y))
@@ -201,6 +202,9 @@ $(obj)/zImage.iseries: vmlinux
 $(obj)/zBoot.%: $(wrapperbits) $(dts)
        $(call if_changed,wrap,$*,$(dts),,,$(obj)/empty.o)
 
+# horrible hack to avoid overlapping calls to wrapper script clobbering dtb.
+$(obj)/zImage.qemu: $(obj)/zBoot.qemu
+
 $(obj)/zImage.ps3: vmlinux  $(wrapper) $(wrapperbits) 
$(srctree)/$(src)/dts/ps3.dts
        $(STRIP) -s -R .comment $< -o vmlinux.strip
        $(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,)
@@ -234,8 +238,8 @@ install: $(CONFIGURE) $(addprefix $(obj)
        sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux 
System.map "$(INSTALL_PATH)" $<
 
 # anything not in $(targets)
-clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* treeImage.* 
\
-       otheros.bld $(kexec-)
+clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* treeImage.*
+clean-files += otheros.bld ppc_rom.bin $(kexec-)
 
 # clean up files cached by wrapper
 clean-kernel := vmlinux.strip vmlinux.bin empty.o.bin
Index: kernel/arch/powerpc/boot/dts/qemu.dts
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/dts/qemu.dts       2007-08-27 20:48:34.000000000 
-0500
@@ -0,0 +1,100 @@
+/*
+ * QEMU PReP skeleton device tree
+ * from PReP skeleton device tree
+ *
+ * Milton Miller
+ */
+
+/ {
+       device_type = "qemu";
+       model = "QEMU,PReP";
+       compatible = "qemu-prep";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               [EMAIL PROTECTED] {
+                       device_type = "cpu";
+                       reg = <0>;
+                       clock-frequency =<d#200000000>;
+                       bus-frequency = <d#100000000>;
+                       timebase-frequency = <d#25000000>;      /* correct? */
+                       i-cache-line-size = <d#32>;
+                       d-cache-line-size = <d#32>;
+                       d-cache-size = <0>;
+                       i-cache-size = <0>;
+
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               // dummy range here, zImage wrapper will fill in the actual
+               // amount of memory from the nvram
+               reg = <00000000 01000000>;
+       };
+
+       [EMAIL PROTECTED] {
+               device_type = "pci";
+               compatible = "prep-pci";
+               clock-frequency = <01fca055>;
+               reg = <80000000 7ffff>;
+               /* 8259-interrupt-acknowledge = <bffffff0>; */
+               #address-cells = <3>;
+               #size-cells = <2>;
+               ranges=<01000000 00000000 00000000 80000000 00000000 00800000
+                       02000000 00000000 00000000 c0000000 00000000 01000000>;
+               interrupt-map-mask = <f800 0 0 7>;
+               interrupt-map = <6000 0 0 1     &PIC8259 6 0
+                                8000 0 0 1     &PIC8259 7 0
+                                9000 0 0 1     &PIC8259 2 0
+                                b000 0 0 1     &PIC8259 1 0>;
+
+               isa {
+                       device_type = "isa";
+                       #address-cells = <2>;
+                       #size-cells = <1>;
+                       #interrupt-cells = <2>;
+                       ranges = <00000001 00000000
+                                 01005800 00000000 00000000  00010000
+                                 00000000 00000000
+                                 02005800 00000000 00000000  01000000>;
+
+                       parallel {
+                               device_type = "parallel";
+                               compatible = "pnpPNP,401", "pnpPNP,400";
+                               reg =  <00000001 000003bc  00000008
+                                       00000001 000007bc  00000006>;
+                               interrupts = <00000007 00000003>;
+                               interrupt-parent = <&PIC8259>;
+                       };
+
+                       [EMAIL PROTECTED] {
+                               device_type = "serial";
+                               compatible = "pnpPNP,501", "pnpPNP,500",
+                                               "ns16550";
+                               virtual-reg = <800003f8>;
+                               clock-frequency = <001c2000>;
+                               reg =  <00000001 000003f8  00000008>;
+                               interrupts = <00000004 00000003>;
+                               interrupt-parent = <&PIC8259>;
+                       };
+                       PIC8259: interrupt-controller {
+                               device_type = "i8259";
+                               compatible = "prep,iic";
+                               interrupt-controller;
+                               reg = < 00000001 00000020  00000002
+                                       00000001 000000a0  00000002
+                                       00000001 000004d0  00000002>;
+                       };
+               };
+       };
+
+       chosen {
+               linux,stdout-path = "/pci/isa/[EMAIL PROTECTED]";
+       };
+};
+
Index: kernel/arch/powerpc/platforms/Kconfig
===================================================================
--- kernel.orig/arch/powerpc/platforms/Kconfig  2007-08-24 05:46:36.000000000 
-0500
+++ kernel/arch/powerpc/platforms/Kconfig       2007-08-24 05:46:58.000000000 
-0500
@@ -47,6 +47,7 @@ source "arch/powerpc/platforms/chrp/Kcon
 source "arch/powerpc/platforms/52xx/Kconfig"
 source "arch/powerpc/platforms/powermac/Kconfig"
 source "arch/powerpc/platforms/prep/Kconfig"
+source "arch/powerpc/platforms/qemu/Kconfig"
 source "arch/powerpc/platforms/maple/Kconfig"
 source "arch/powerpc/platforms/pasemi/Kconfig"
 source "arch/powerpc/platforms/celleb/Kconfig"
Index: kernel/arch/powerpc/boot/wrapper
===================================================================
--- kernel.orig/arch/powerpc/boot/wrapper       2007-08-24 05:46:36.000000000 
-0500
+++ kernel/arch/powerpc/boot/wrapper    2007-08-27 22:49:09.000000000 -0500
@@ -320,4 +320,53 @@ ps3)
 
     gzip --force -9 --stdout "$ofile.bin" > "$object/otheros.bld"
     ;;
+qemu)
+    # this part makes the zBoot.qemu a bootrom for qemu.
+    #
+    # the qemu bootrom is 512k , located at the top of the 32 bit address
+    # space.   The fixed entrypoint is address -4.
+
+    copy_rom_start=0x`${CROSS}nm "$ofile" \
+        | grep ' copy_rom_start$'       \
+        | cut -d' ' -f1`
+    copy_rom_start=`printf "%d" $copy_rom_start`
+    copy_rom_end=0x`${CROSS}nm "$ofile" \
+        | grep ' copy_rom_end$'       \
+        | cut -d' ' -f1`
+    copy_rom_end=`printf "%d" $copy_rom_end`
+    rom_start=0x`${CROSS}nm "$ofile" \
+        | grep ' _start$'       \
+        | cut -d' ' -f1`
+
+    rom_start=`printf "%d" $rom_start`
+    rom_size=$((1<<19))
+    copy_rom_len=$(($copy_rom_end-$copy_rom_start))
+    copy_rom_dst=$(($rom_size-$copy_rom_len))
+    copy_rom_src=$(($copy_rom_start-$rom_start))
+
+    img_size=`${CROSS}size "$ofile" | tail -n1 | cut -f4`
+    if [ $img_size -gt $copy_rom_dst ]
+    then
+       echo Image "${ofile##*/}" too big to fit in rom, skipping rom build.
+    else
+       romfile="$object/ppc_rom.bin"
+       tmpfile="$object/ppc_rom.$$"
+
+       rm -f "$tmpfile"
+       ${CROSS}objcopy -O binary --pad-to=$(($rom_size+$rom_start)) \
+           --gap-fill=0xff  "$ofile" "$tmpfile"
+
+       msg=$(dd if="$tmpfile" of="$tmpfile" conv=notrunc \
+           skip=$copy_rom_src seek=$copy_rom_dst      \
+           count=$copy_rom_len bs=1 2>&1)
+
+       if [ $? -ne "0" ]; then
+           echo $msg
+           rm -f "$tmpfile"
+           exit 2
+       fi
+
+       mv "$tmpfile" "$romfile"
+    fi
+    ;;
 esac
Index: kernel/arch/powerpc/platforms/qemu/Kconfig
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/platforms/qemu/Kconfig  2007-08-24 05:46:58.000000000 
-0500
@@ -0,0 +1,10 @@
+config PPC_QEMU
+       bool "PowerPC Reference Platform (PReP) based QEMU emulated systems"
+       depends on PPC_MULTIPLATFORM && PPC32
+       select PPC_I8259
+       select PPC_INDIRECT_PCI
+       select PPC_UDBG_16550
+       select PPC_NATIVE
+       select WANT_DEVICE_TREE
+       default n
+
Index: kernel/arch/powerpc/platforms/qemu/Makefile
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/platforms/qemu/Makefile 2007-08-24 05:46:58.000000000 
-0500
@@ -0,0 +1,2 @@
+obj-y                  += setup.o
+obj-$(CONFIG_PCI)      += pci.o
Index: kernel/arch/powerpc/platforms/qemu/pci.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/platforms/qemu/pci.c    2007-08-27 20:14:37.000000000 
-0500
@@ -0,0 +1,133 @@
+/*
+ * Port to arch/powerpc:
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * Port to qemu:
+ * Copyright 2007 Milton Miller, IBM Corporation.
+ *
+ * Based on OpenHackware 0.4
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * pci config based on arch/powerpc/platforms/chrp/pci.c GoldenGate code
+ *
+ */
+
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/udbg.h>
+
+static volatile void __iomem *qemu_config_addr(struct pci_bus *bus,
+       unsigned int devfn, int off)
+{
+       int dev, fn;
+       struct pci_controller *hose = bus->sysdata;
+
+       if (!hose->cfg_data)
+               return NULL;
+
+       if (bus->number != 0)
+               return NULL;
+
+       dev = devfn >> 3;
+       fn = devfn & 7;
+
+       if (dev < 11 || dev > 21)
+               return NULL;
+
+       return hose->cfg_data + ((1 << dev) | (fn << 8) | off);
+}
+
+int qemu_read_config(struct pci_bus *bus, unsigned int devfn, int off,
+                          int len, u32 *val)
+{
+       volatile void __iomem *cfg_data = qemu_config_addr(bus, devfn, off);
+
+       /* check, should this be 0? */
+       if (cfg_data == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       /*
+        * Note: the caller has already checked that off is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               *val =  in_8(cfg_data);
+               break;
+       case 2:
+               *val = in_le16(cfg_data);
+               break;
+       default:
+               *val = in_le32(cfg_data);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int qemu_write_config(struct pci_bus *bus, unsigned int devfn, int off,
+                           int len, u32 val)
+{
+       volatile void __iomem *cfg_data = qemu_config_addr(bus, devfn, off);
+
+       if (cfg_data == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * Note: the caller has already checked that off is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               out_8(cfg_data, val);
+               break;
+       case 2:
+               out_le16(cfg_data, val);
+               break;
+       default:
+               out_le32(cfg_data, val);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops qemu_pci_ops =
+{
+       qemu_read_config,
+       qemu_write_config
+};
+
+void __init qemu_find_bridges(void)
+{
+       struct device_node *phb;
+       struct pci_controller *hose;
+
+       phb = of_find_node_by_type(NULL, "pci");
+       if (!phb) {
+               printk(KERN_ERR "PReP: Cannot find PCI bridge OF node\n");
+               return;
+       }
+
+       hose = pcibios_alloc_controller(phb);
+       if (!hose)
+               return;
+
+       pci_process_bridge_OF_ranges(hose, phb, 1);
+
+#define PREP_PCI_DRAM_OFFSET   0x80000000
+
+       pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+       ISA_DMA_THRESHOLD = 0x00ffffff;
+       DMA_MODE_READ = 0x44;
+       DMA_MODE_WRITE = 0x48;
+
+       hose->cfg_data = ioremap(0x80000000, 1 << 22);
+
+       hose->ops = &qemu_pci_ops;
+
+       udbg_init_uart(hose->io_base_virt + 0x3f8, 0, 0);
+       register_early_udbg_console();
+       printk(KERN_INFO "qemu_find_bridges: config at %p\n", hose->cfg_data);
+}
+
Index: kernel/arch/powerpc/platforms/qemu/setup.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/platforms/qemu/setup.c  2007-08-27 20:24:59.000000000 
-0500
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 1995  Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan ([EMAIL PROTECTED])
+ *
+ * Support for PReP (Motorola MTX/MVME)
+ * by Troy Benjegerdes ([EMAIL PROTECTED])
+ *
+ * Port to arch/powerpc:
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * Port to qemu:
+ * Copyright 2007 Milton Miller, IBM Corporation.
+ *
+ * Based on OpenHackware 0.4
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <linux/initrd.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+/* #include <asm/mpic.h> */
+#include <asm/i8259.h>
+#include <asm/time.h>
+#include <asm/udbg.h>
+
+static const char *qemu_model = "(unknown)";
+
+extern void qemu_find_bridges(void);
+
+#if 0
+
+/* useful ISA ports */
+#define PREP_SYSCTL    0x81c
+/* present in the IBM reference design; possibly identical in Mot boxes: */
+#define PREP_IBM_PM1   0x82a   /* power management register 1 */
+#define PREP_IBM_PLANAR        0x852   /* planar ID - identifies the 
motherboard */
+#define PREP_IBM_DISP  0x8c0   /* 4-digit LED display */
+
+
+
+
+/* Used by all Motorola PReP */
+static void prep_restart(char *cmd)
+{
+       local_irq_disable(); /* no interrupts */
+
+       /* set exception prefix high - to the prom */
+       mtmsr(mfmsr() | MSR_IP);
+
+       /* make sure bit 0 (reset) is a 0 */
+       outb(inb(0x92) & ~1L, 0x92);
+       /* signal a reset to system control port A - soft reset */
+       outb(inb(0x92) | 1, 0x92);
+
+       for (;;)
+               ;
+       /* not reached */
+}
+
+static void prep_halt(void)
+{
+       local_irq_disable(); /* no interrupts */
+
+       /* set exception prefix high - to the prom */
+       mtmsr(mfmsr() | MSR_IP);
+
+       for (;;)
+               ;
+       /* not reached */
+}
+
+/*
+ * On most IBM PReP's, power management is handled by a Signetics 87c750
+ * behind the Utah component on the ISA bus. To access the 750 you must write
+ * a series of nibbles to port 0x82a (decoded by the Utah). This is described
+ * somewhat in the IBM Carolina Technical Specification.
+ * -Hollis
+ */
+static void
+utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
+{
+       /*
+        * byte1: 0 0 0 1 0  d  a5 a4
+        * byte2: 0 0 0 1 a3 a2 a1 a0
+        *
+        * d = the bit's value, enabled or disabled
+        * (a5 a4 a3) = the byte number, minus 20
+        * (a2 a1 a0) = the bit number
+        *
+        * example: set the 5th bit of byte 21 (21.5)
+        *     a5 a4 a3 = 001 (byte 1)
+        *     a2 a1 a0 = 101 (bit 5)
+        *
+        *     byte1 = 0001 0100 (0x14)
+        *     byte2 = 0001 1101 (0x1d)
+        */
+       unsigned char byte1=0x10, byte2=0x10;
+
+       /* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
+       bytenum -= 20;
+
+       byte1 |= (!!value) << 2;                /* set d */
+       byte1 |= (bytenum >> 1) & 0x3;  /* set a5, a4 */
+
+       byte2 |= (bytenum & 0x1) << 3;  /* set a3 */
+       byte2 |= bitnum & 0x7;                  /* set a2, a1, a0 */
+
+       outb(byte1, PREP_IBM_PM1);      /* first nibble */
+       mb();
+       udelay(100);                            /* important: let controller 
recover */
+
+       outb(byte2, PREP_IBM_PM1);      /* second nibble */
+       mb();
+       udelay(100);                            /* important: let controller 
recover */
+}
+
+static void prep_sig750_poweroff(void)
+{
+       /* tweak the power manager found in most IBM PRePs (except Thinkpads) */
+
+       local_irq_disable();
+       /* set exception prefix high - to the prom */
+       mtmsr(mfmsr() | MSR_IP);
+
+       utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
+
+       for (;;)
+               ;
+       /* not reached */
+}
+
+#endif
+
+/* cpuinfo code common to all IBM PReP */
+static void qemu_ibm_cpuinfo(struct seq_file *m)
+{
+       seq_printf(m, "machine\t\t: PReP %s\n", qemu_model);
+}
+
+#define NVRAM_AS0 0x74
+#define NVRAM_AS1 0x75
+#define NVRAM_DAT 0x77
+
+static unsigned char qemu_nvram_read_val(int addr)
+{
+       outb(NVRAM_AS0, addr & 0xff);
+       outb(NVRAM_AS1, (addr >> 8) & 0xff);
+       return inb(NVRAM_DAT);
+}
+
+
+static void qemu_nvram_write_val(int addr, unsigned char val)
+{
+       outb(NVRAM_AS0, addr & 0xff);
+       outb(NVRAM_AS1, (addr >> 8) & 0xff);
+       outb(NVRAM_DAT, val);
+}
+
+
+static void __init qemu_setup_arch(void)
+{
+       struct device_node *root;
+       const char *model;
+
+       root = of_find_node_by_path("/");
+       model = of_get_property(root, "model", NULL);
+       of_node_put(root);
+       if (model)
+               qemu_model = model;
+
+       /* init to some ~sane value until calibrate_delay() runs */
+       /* loops_per_jiffy = 50000000; */
+
+       /* Lookup PCI host bridges */
+       qemu_find_bridges();
+
+       /* Read in NVRAM data */
+/*     init_qemu_nvram(); */
+}
+
+static void __init qemu_find_8259(void)
+{
+       struct device_node *pic = NULL;
+       unsigned long int_ack = 0;
+
+       pic = of_find_node_by_type(NULL, "i8259");
+       if (!pic) {
+               printk(KERN_ERR "No interrupt controller found!\n");
+               return;
+       }
+
+       /* polling */
+       i8259_init(pic, int_ack);
+       ppc_md.get_irq = i8259_irq;
+
+       /* hack: set default host until interrupt map and pci fixed */
+       irq_set_default_host(i8259_get_host());
+}
+
+static void __init qemu_init_IRQ(void)
+{
+       qemu_find_8259();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+static int qemu_ide_default_irq(unsigned long base)
+{
+       switch (base) {
+       case 0x1f0: return 13;
+       case 0x170: return 13;
+       case 0x1e8: return 11;
+       case 0x168: return 10;
+       case 0xfff0: return 14;         /* MCP(N)750 ide0 */
+       case 0xffe0: return 15;         /* MCP(N)750 ide1 */
+       default: return 0;
+       }
+}
+
+static unsigned long qemu_ide_default_io_base(int index)
+{
+       switch (index) {
+       case 0: return 0x1f0;
+       case 1: return 0x170;
+       case 2: return 0x1e8;
+       case 3: return 0x168;
+       default:
+               return 0;
+       }
+}
+#endif
+
+#if 0
+static int __init prep_request_io(void)
+{
+#ifdef CONFIG_NVRAM
+       request_region(PREP_NVRAM_AS0, 0x8, "nvram");
+#endif
+       request_region(0x00,0x20,"dma1");
+       request_region(0x40,0x20,"timer");
+       request_region(0x80,0x10,"dma page reg");
+       request_region(0xc0,0x20,"dma2");
+
+       return 0;
+}
+device_initcall(prep_request_io);
+#endif
+
+
+static int __init qemu_probe(void)
+{
+       if (! of_flat_dt_is_compatible(of_get_flat_dt_root(), "qemu-prep"))
+               return 0;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+       ppc_ide_md.default_irq = qemu_ide_default_irq;
+       ppc_ide_md.default_io_base = qemu_ide_default_io_base;
+#endif
+
+       return 1;
+}
+
+define_machine(qemu) {
+       .name                   = "QEMU",
+       .probe                  = qemu_probe,
+       .setup_arch             = qemu_setup_arch,
+       .progress               = udbg_progress,
+       .show_cpuinfo           = qemu_ibm_cpuinfo,
+       .init_IRQ               = qemu_init_IRQ,
+/*     .pcibios_fixup          = qemu_pcibios_fixup, */
+/*     .restart                = qemu_restart, */
+/*     .power_off              = qemu_halt, */
+/*     .halt                   = qemu_halt, */
+/*     .time_init              = todc_time_init, */
+/*     .set_rtc_time           = todc_set_rtc_time, */
+/*     .get_rtc_time           = todc_get_rtc_time, */
+       .calibrate_decr         = generic_calibrate_decr,
+       .nvram_read_val         = qemu_nvram_read_val,
+       .nvram_write_val        = qemu_nvram_write_val,
+       .phys_mem_access_prot   = pci_phys_mem_access_prot,
+};
Index: kernel/arch/powerpc/platforms/Makefile
===================================================================
--- kernel.orig/arch/powerpc/platforms/Makefile 2007-08-24 05:46:36.000000000 
-0500
+++ kernel/arch/powerpc/platforms/Makefile      2007-08-24 05:46:58.000000000 
-0500
@@ -7,6 +7,7 @@ endif
 endif
 obj-$(CONFIG_PPC_CHRP)         += chrp/
 obj-$(CONFIG_PPC_PREP)         += prep/
+obj-$(CONFIG_PPC_QEMU)         += qemu/
 #obj-$(CONFIG_4xx)             += 4xx/
 obj-$(CONFIG_44x)              += 44x/
 obj-$(CONFIG_PPC_MPC52xx)      += 52xx/
Index: kernel/arch/powerpc/boot/.gitignore
===================================================================
--- kernel.orig/arch/powerpc/boot/.gitignore    2007-08-27 21:10:42.000000000 
-0500
+++ kernel/arch/powerpc/boot/.gitignore 2007-08-27 21:11:02.000000000 -0500
@@ -17,6 +17,7 @@ infutil.h
 kernel-vmlinux.strip.c
 kernel-vmlinux.strip.gz
 mktree
+ppc_rom.bin
 uImage
 cuImage.*
 zImage
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to