[MIPS] Ranchu Virtual platform with DT support
authorMiodrag Dinic <miodrag.dinic@imgtec.com>
Thu, 27 Nov 2014 15:08:16 +0000 (16:08 +0100)
committerRaghu Gandham <raghu.gandham@imgtec.com>
Tue, 2 Dec 2014 23:29:52 +0000 (15:29 -0800)
Ranchu Virtual platform is a Goldfish based platform
enriched with device tree support. This platform is
backed up by QEMU with the "ranchu" machine which
represents the new virtual board which will be used for
running Android.

The new Ranchu platform introduces support for running Virtio
devices in purpose of reducing the number of Goldfish devices
used by the old Goldfish platform. For example, it uses
virtio-block devices to emulate the Goldfish NAND.

Change-Id: I3a508d0a0ddc3c9d5bf777445ab739f465ab9471
Reviewed-on: https://mipsia.review.mips.com/2859
Reviewed-by: Raghu Gandham <raghu.gandham@imgtec.com>
Tested-by: Raghu Gandham <raghu.gandham@imgtec.com>
18 files changed:
arch/mips/Kbuild.platforms
arch/mips/Kconfig
arch/mips/goldfish/Makefile [new file with mode: 0644]
arch/mips/goldfish/Platform [new file with mode: 0644]
arch/mips/goldfish/goldfish-interrupt.c [new file with mode: 0644]
arch/mips/goldfish/goldfish-platform.c [new file with mode: 0644]
arch/mips/goldfish/goldfish-time.c [new file with mode: 0644]
arch/mips/goldfish/include/mach/hardware.h [new file with mode: 0644]
arch/mips/goldfish/include/mach/irq.h [new file with mode: 0644]
arch/mips/goldfish/include/mach/time.h [new file with mode: 0644]
arch/mips/goldfish/pm.c [new file with mode: 0644]
arch/mips/goldfish/ranchu.dts [new file with mode: 0644]
arch/mips/goldfish/switch.c [new file with mode: 0644]
arch/mips/include/asm/mach-goldfish/hardware.h [new file with mode: 0644]
arch/mips/include/asm/mach-goldfish/irq.h [new file with mode: 0644]
arch/mips/include/asm/mach-goldfish/time.h [new file with mode: 0644]
arch/mips/include/asm/mach-goldfish/war.h [new file with mode: 0644]
arch/mips/kernel/proc.c

index 4b597d91a8d5f2c44ed1f50ea0b11270d711f124..3a2f8283611aba815f70dc0bf25b69d1f763c29f 100644 (file)
@@ -9,6 +9,7 @@ platforms += cavium-octeon
 platforms += cobalt
 platforms += dec
 platforms += emma
+platforms += goldfish
 platforms += jazz
 platforms += jz4740
 platforms += lantiq
index 33bef7cd082d18e23c128bc42d741e91d546e778..79ca0e2a699b22952098f1af85f06451e71d63b2 100644 (file)
@@ -289,8 +289,8 @@ config MACH_LOONGSON1
          the ICT (Institute of Computing Technology) and the Chinese Academy
          of Sciences.
 
-config MIPS_GOLDFISH
-       bool "Goldfish (Virtual Platform)"
+config MIPS_RANCHU
+       bool "Ranchu (Virtual Platform)"
        select BOOT_ELF32
        select BOOT_RAW
        select CEVT_R4K
@@ -1857,6 +1857,23 @@ config KVM_HOST_FREQ
          RTC emulation when determining guest CPU Frequency.  Instead, the guest
          processor frequency is automatically derived from the host frequency.
 
+config 64BIT_PHYS_ADDR
+       bool "Kernel supports 64 bit physical addresses" if EXPERIMENTAL
+       depends on 64BIT
+       help
+         Defines 64 bit physical addresses in kernel.
+         Increases page table sizes.
+
+         It is an alternative for HIGHMEM usage of huge physical memory.
+         Requires 64bit capable CPU and 64 bit kernel code model.
+
+         Note: without this option kernel can support up to 4GB physical
+         memory for 4KB pages and up to 64GB for 64KB pages.
+
+config ARCH_PHYS_ADDR_T_64BIT
+       def_bool 64BIT_PHYS_ADDR
+
+
 choice
        prompt "Kernel page size"
        default PAGE_SIZE_4KB
@@ -2145,12 +2162,6 @@ config SB1_PASS_2_1_WORKAROUNDS
        default y
 
 
-config 64BIT_PHYS_ADDR
-       bool
-
-config ARCH_PHYS_ADDR_T_64BIT
-       def_bool 64BIT_PHYS_ADDR
-
 config CPU_HAS_SMARTMIPS
        depends on SYS_SUPPORTS_SMARTMIPS
        bool "Support for the SmartMIPS ASE"
diff --git a/arch/mips/goldfish/Makefile b/arch/mips/goldfish/Makefile
new file mode 100644 (file)
index 0000000..e48f32c
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Makefile for Goldfish virtual platform
+#
+
+EXTRA_CFLAGS += -Wno-error
+
+obj-$(CONFIG_GOLDFISH) += goldfish-platform.o
+obj-$(CONFIG_GOLDFISH) += goldfish-interrupt.o
+obj-$(CONFIG_GOLDFISH) += goldfish-time.o
+obj-$(CONFIG_GOLDFISH) += switch.o
+obj-$(CONFIG_GOLDFISH) += pm.o
+
+obj-$(CONFIG_MIPS_RANCHU)      += ranchu.dtb.o
+
+$(obj)/%.dtb: $(obj)/%.dts
+       $(call if_changed,dtc)
diff --git a/arch/mips/goldfish/Platform b/arch/mips/goldfish/Platform
new file mode 100644 (file)
index 0000000..1dc5cb4
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Goldfish
+#
+platform-$(CONFIG_GOLDFISH)   := goldfish/
+cflags-$(CONFIG_GOLDFISH)  += -Iarch/mips/include/asm/mach-goldfish -Iarch/mips/goldfish/include
+load-$(CONFIG_GOLDFISH)    += 0xffffffff80010000
+all-$(CONFIG_GOLDFISH)     := $(COMPRESSION_FNAME).bin
+
diff --git a/arch/mips/goldfish/goldfish-interrupt.c b/arch/mips/goldfish/goldfish-interrupt.c
new file mode 100644 (file)
index 0000000..46d85a6
--- /dev/null
@@ -0,0 +1,153 @@
+/* arch/mips/mach-goldfish/goldfish-platform.c
+**
+** Copyright (C) 2007 Google, Inc.
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+**
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/irqchip.h>
+#include <linux/of.h>
+
+#include <mach/hardware.h>
+#include <mach/irq.h>
+#include <asm/io.h>
+#include <asm/irq_cpu.h>
+#include <asm/setup.h>
+
+#define GOLDFISH_INTERRUPT_STATUS       0x00 // number of pending interrupts
+#define GOLDFISH_INTERRUPT_NUMBER       0x04
+#define GOLDFISH_INTERRUPT_DISABLE_ALL  0x08
+#define GOLDFISH_INTERRUPT_DISABLE      0x0c
+#define GOLDFISH_INTERRUPT_ENABLE       0x10
+
+static void __iomem *goldfish_interrupt;
+
+void goldfish_mask_irq(struct irq_data *d)
+{
+       writel(d->irq-GOLDFISH_IRQ_BASE,
+              goldfish_interrupt + GOLDFISH_INTERRUPT_DISABLE);
+}
+
+void goldfish_unmask_irq(struct irq_data *d)
+{
+       writel(d->irq-GOLDFISH_IRQ_BASE,
+              goldfish_interrupt + GOLDFISH_INTERRUPT_ENABLE);
+}
+
+static struct irq_chip goldfish_irq_chip = {
+       .name   = "goldfish",
+       .irq_mask       = goldfish_mask_irq,
+       .irq_mask_ack = goldfish_mask_irq,
+       .irq_unmask = goldfish_unmask_irq,
+};
+
+void goldfish_init_irq(void)
+{
+       unsigned int i;
+       uint32_t base;
+       struct device_node *dn;
+
+       if ((dn = of_find_node_by_name(NULL, "goldfish_pic")) == NULL) {
+               panic("goldfish_init_irq() failed to "
+                         "fetch device node \'goldfish-pic\'!\n");
+       }
+
+       if (of_property_read_u32(dn, "reg", &base) < 0) {
+               panic("goldfish_init_irq() failed to "
+                         "fetch device base address property \'reg\'!\n");
+       }
+
+       goldfish_interrupt = IO_ADDRESS(base);
+
+       /*
+        * Disable all interrupt sources
+        */
+       writel(1, goldfish_interrupt + GOLDFISH_INTERRUPT_DISABLE_ALL);
+
+       for (i = GOLDFISH_IRQ_BASE; i < GOLDFISH_IRQ_BASE+32; i++) {
+               irq_set_chip(i, &goldfish_irq_chip);
+               irq_set_handler(i, handle_level_irq);
+#if 0
+               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+#endif
+       }
+}
+
+void goldfish_irq_dispatch(void)
+{
+       uint32_t irq;
+       /*
+        * Disable all interrupt sources
+        */
+       irq = readl(goldfish_interrupt + GOLDFISH_INTERRUPT_NUMBER);
+       do_IRQ(GOLDFISH_IRQ_BASE+irq);
+}
+
+void goldfish_fiq_dispatch(void)
+{
+       panic("goldfish_fiq_dispatch");
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+       if (pending & CAUSEF_IP2)
+               goldfish_irq_dispatch();
+       else if (pending & CAUSEF_IP3)
+               goldfish_fiq_dispatch();
+       else if (pending & CAUSEF_IP7)
+               do_IRQ(MIPS_CPU_IRQ_BASE + 7);
+       else
+               spurious_interrupt();
+}
+
+static struct irqaction cascade = {
+       .handler        = no_action,
+       .flags      = IRQF_NO_THREAD,
+       .name           = "cascade",
+};
+
+static void mips_timer_dispatch(void)
+{
+       do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IRQ_COMPARE);
+}
+
+void __init goldfish_pic_init(struct device_node *node, struct device_node *parent)
+{
+       mips_cpu_irq_init();
+       goldfish_init_irq();
+
+       if (cpu_has_vint) {
+               set_vi_handler(MIPS_CPU_IRQ_PIC, goldfish_irq_dispatch);
+               set_vi_handler(MIPS_CPU_IRQ_PIC, goldfish_fiq_dispatch);
+       }
+       setup_irq(MIPS_CPU_IRQ_BASE+MIPS_CPU_IRQ_PIC, &cascade);
+       setup_irq(MIPS_CPU_IRQ_BASE+MIPS_CPU_IRQ_FIQ, &cascade);
+
+       if (cpu_has_vint)
+               set_vi_handler(MIPS_CPU_IRQ_COMPARE, mips_timer_dispatch);
+}
+
+void __init arch_init_irq(void)
+{
+       irqchip_init();
+}
+
+static const struct of_device_id irqchip_of_match_goldfish_pic
+__used __section(__irqchip_of_table)
+= { .compatible = "generic,goldfish-pic", .data = goldfish_pic_init };
diff --git a/arch/mips/goldfish/goldfish-platform.c b/arch/mips/goldfish/goldfish-platform.c
new file mode 100644 (file)
index 0000000..63139f2
--- /dev/null
@@ -0,0 +1,96 @@
+/* arch/mips/mach-goldfish/goldfish-platform.c
+**
+** Copyright (C) 2007 Google, Inc.
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+**
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/bootmem.h>
+
+#include <mach/hardware.h>
+#include <mach/irq.h>
+#include <asm/io.h>
+#include <asm/bootinfo.h>
+#include <asm/mips-boards/generic.h>
+
+void __init prom_init(void)
+{
+       char *cmdline = (char *)fw_arg0;
+       strcpy(arcs_cmdline, cmdline);
+}
+
+void prom_free_prom_memory(void)
+{
+}
+
+#ifdef CONFIG_64BIT
+#define GOLDFISH_TTY_PUT_CHAR (*(volatile unsigned int *)0xffffffffbf002000)
+#else
+#define GOLDFISH_TTY_PUT_CHAR (*(volatile unsigned int *)0xbf002000)
+#endif
+
+void prom_putchar(int c)
+{
+       GOLDFISH_TTY_PUT_CHAR = c;
+}
+
+const char *get_system_type(void)
+{
+       return "MIPS-Goldfish";
+}
+
+void __init plat_mem_setup(void)
+{
+       /*
+        * Load the builtin devicetree. This causes the chosen node to be
+        * parsed resulting in our memory appearing
+        */
+       __dt_setup_arch(&__dtb_start);
+}
+
+void __init device_tree_init(void)
+{
+       unsigned long base, size;
+
+       if (!initial_boot_params)
+               return;
+
+       base = virt_to_phys((void *)initial_boot_params);
+       size = be32_to_cpu(initial_boot_params->totalsize);
+
+       /* Before we do anything, lets reserve the dt blob */
+       reserve_bootmem(base, size, BOOTMEM_DEFAULT);
+
+       unflatten_device_tree();
+}
+
+static struct of_device_id __initdata goldfish_ids[] = {
+       { .compatible = "simple-bus", },
+       {},
+};
+
+int __init plat_of_setup(void)
+{
+       if (!of_have_populated_dt())
+               panic("device tree not present");
+
+       return of_platform_populate(NULL, goldfish_ids, NULL, NULL);
+}
+
+arch_initcall(plat_of_setup);
diff --git a/arch/mips/goldfish/goldfish-time.c b/arch/mips/goldfish/goldfish-time.c
new file mode 100644 (file)
index 0000000..7ce637a
--- /dev/null
@@ -0,0 +1,112 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/of.h>
+
+#include <mach/hardware.h>
+#include <mach/irq.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/bootinfo.h>
+#include <asm/div64.h>
+
+#define GOLDFISH_TIMER_LOW             0x00
+#define GOLDFISH_TIMER_HIGH            0x04
+
+/*
+ * Estimate CPU frequency.  Sets mips_hpt_frequency as a side-effect
+ */
+static unsigned int __init estimate_cpu_frequency(void)
+{
+       uint32_t base;
+       struct device_node *dn;
+       void __iomem *rtc_base;
+       unsigned int start, count;
+       unsigned long rtcstart, rtcdelta;
+       unsigned int prid = read_c0_prid() & 0xffff00;
+
+       if ((dn = of_find_node_by_name(NULL, "goldfish_timer")) == NULL) {
+               panic("goldfish_timer_init() failed to "
+                         "fetch device node \'goldfish-timer\'!\n");
+       }
+
+       if (of_property_read_u32(dn, "reg", &base) < 0) {
+               panic("goldfish_timer_init() failed to "
+                         "fetch device base address property \'reg\'!\n");
+       }
+
+       rtc_base = IO_ADDRESS(base);
+
+       /*
+        * poll the nanosecond resolution RTC for 1s
+        * to calibrate the CPU frequency
+        */
+       rtcstart = readl(rtc_base+GOLDFISH_TIMER_LOW);
+       start = read_c0_count();
+       do {
+               rtcdelta = readl(rtc_base+GOLDFISH_TIMER_LOW) - rtcstart;
+       } while (rtcdelta < 1000000000);
+       count = read_c0_count() - start;
+
+       mips_hpt_frequency = count;
+       if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
+           (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
+               count *= 2;
+
+       count += 5000;    /* round */
+       count -= count%10000;
+
+       return count;
+}
+
+unsigned long cpu_khz;
+
+void plat_time_init(void)
+{
+       unsigned int est_freq;
+
+       est_freq = estimate_cpu_frequency();
+
+       printk(KERN_INFO "CPU frequency %d.%02d MHz\n", est_freq/1000000,
+              (est_freq%1000000)*100/1000000);
+
+       cpu_khz = est_freq / 1000;
+
+}
+
+/**
+ * save_time_delta - Save the offset between system time and RTC time
+ * @delta: pointer to timespec to store delta
+ * @rtc: pointer to timespec for current RTC time
+ *
+ * Return a delta between the system time and the RTC time, such
+ * that system time can be restored later with restore_time_delta()
+ */
+void save_time_delta(struct timespec *delta, struct timespec *rtc)
+{
+       set_normalized_timespec(delta,
+                               __current_kernel_time().tv_sec - rtc->tv_sec,
+                               __current_kernel_time().tv_nsec - rtc->tv_nsec);
+}
+EXPORT_SYMBOL(save_time_delta);
+
+/**
+ * restore_time_delta - Restore the current system time
+ * @delta: delta returned by save_time_delta()
+ * @rtc: pointer to timespec for current RTC time
+ */
+void restore_time_delta(struct timespec *delta, struct timespec *rtc)
+{
+       struct timespec ts;
+
+       set_normalized_timespec(&ts,
+                               delta->tv_sec + rtc->tv_sec,
+                               delta->tv_nsec + rtc->tv_nsec);
+
+       do_settimeofday(&ts);
+}
+EXPORT_SYMBOL(restore_time_delta);
diff --git a/arch/mips/goldfish/include/mach/hardware.h b/arch/mips/goldfish/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..ce054f1
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef CONFIG_GOLDFISH
+#include <asm/mach-goldfish/hardware.h>
+#endif
diff --git a/arch/mips/goldfish/include/mach/irq.h b/arch/mips/goldfish/include/mach/irq.h
new file mode 100644 (file)
index 0000000..10ffa67
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef CONFIG_GOLDFISH
+#include <asm/mach-goldfish/irq.h>
+#endif
diff --git a/arch/mips/goldfish/include/mach/time.h b/arch/mips/goldfish/include/mach/time.h
new file mode 100644 (file)
index 0000000..984ed3a
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef CONFIG_GOLDFISH
+#include <asm/mach-goldfish/time.h>
+#endif
diff --git a/arch/mips/goldfish/pm.c b/arch/mips/goldfish/pm.c
new file mode 100644 (file)
index 0000000..745c173
--- /dev/null
@@ -0,0 +1,45 @@
+/* arch/arm/mach-msm/pm.c
+ *
+ * Goldfish Power Management Routines
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+
+extern void (*cpu_wait)(void);
+
+static int goldfish_pm_enter(suspend_state_t state)
+{
+       if (cpu_wait)
+               (*cpu_wait)();
+       return 0;
+}
+
+static struct platform_suspend_ops goldfish_pm_ops = {
+       .enter          = goldfish_pm_enter,
+       .valid          = suspend_valid_only_mem,
+};
+
+static int __init goldfish_pm_init(void)
+{
+       suspend_set_ops(&goldfish_pm_ops);
+       return 0;
+}
+
+device_initcall(goldfish_pm_init);
+
diff --git a/arch/mips/goldfish/ranchu.dts b/arch/mips/goldfish/ranchu.dts
new file mode 100644 (file)
index 0000000..0b618f1
--- /dev/null
@@ -0,0 +1,180 @@
+/dts-v1/;
+
+/ {
+       interrupt-parent = <0x8000>;
+       #size-cells = <0x1>;
+       #address-cells = <0x1>;
+       compatible = "mti,goldfish";
+        model = "ranchu";
+
+       virtio_mmio@1f011e00 {
+               interrupts = <0x27>;
+               reg = <0x1f011e00 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f011c00 {
+               interrupts = <0x26>;
+               reg = <0x1f011c00 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f011a00 {
+               interrupts = <0x25>;
+               reg = <0x1f011a00 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f011800 {
+               interrupts = <0x24>;
+               reg = <0x1f011800 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f011600 {
+               interrupts = <0x23>;
+               reg = <0x1f011600 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f011400 {
+               interrupts = <0x22>;
+               reg = <0x1f011400 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f011200 {
+               interrupts = <0x21>;
+               reg = <0x1f011200 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f011000 {
+               interrupts = <0x20>;
+               reg = <0x1f011000 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f010e00 {
+               interrupts = <0x1f>;
+               reg = <0x1f010e00 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f010c00 {
+               interrupts = <0x1e>;
+               reg = <0x1f010c00 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f010a00 {
+               interrupts = <0x1d>;
+               reg = <0x1f010a00 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f010800 {
+               interrupts = <0x1c>;
+               reg = <0x1f010800 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f010600 {
+               interrupts = <0x1b>;
+               reg = <0x1f010600 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f010400 {
+               interrupts = <0x1a>;
+               reg = <0x1f010400 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f010200 {
+               interrupts = <0x19>;
+               reg = <0x1f010200 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       virtio_mmio@1f010000 {
+               interrupts = <0x18>;
+               reg = <0x1f010000 0x200>;
+               compatible = "virtio,mmio";
+       };
+
+       goldfish_timer@1f005000 {
+               interrupts = <0xd>;
+               reg = <0x1f005000 0x1000>;
+               compatible = "generic,goldfish-timer";
+       };
+
+       goldfish_rtc@1f006000 {
+               interrupts = <0xe>;
+               reg = <0x1f006000 0x1000>;
+               compatible = "generic,goldfish-rtc";
+       };
+
+       goldfish_battery@1f007000 {
+               interrupts = <0xf>;
+               reg = <0x1f007000 0x1000>;
+               compatible = "generic,goldfish-battery";
+       };
+
+       goldfish_fb@1f008000 {
+               interrupts = <0x10>;
+               reg = <0x1f008000 0x100>;
+               compatible = "generic,goldfish-fb";
+       };
+
+       goldfish_events@1f009000 {
+               interrupts = <0x11>;
+               reg = <0x1f009000 0x1000>;
+               compatible = "generic,goldfish-events-keypad";
+       };
+
+       android_pipe@1f00a000 {
+               interrupts = <0x12>;
+               reg = <0x1f00a000 0x2000>;
+               compatible = "generic,android-pipe";
+       };
+
+       goldfish_tty@1f004000 {
+               interrupts = <0xc>;
+               reg = <0x1f004000 0x1000>;
+               compatible = "generic,goldfish-tty";
+       };
+
+       goldfish_tty@1f003000 {
+               interrupts = <0xb>;
+               reg = <0x1f003000 0x1000>;
+               compatible = "generic,goldfish-tty";
+       };
+
+       goldfish_tty@1f002000 {
+               interrupts = <0xa>;
+               reg = <0x1f002000 0x1000>;
+               compatible = "generic,goldfish-tty";
+       };
+
+       goldfish_pic@1f000000 {
+               #interrupt-cells = <0x1>;
+               phandle = <0x8000>;
+               interrupt-controller;
+               reg = <0x1f000000 0x1000>;
+               compatible = "generic,goldfish-pic";
+       };
+
+       memory {
+               reg = <0x0 0x1f000000>;
+               device_type = "memory";
+       };
+
+       cpus {
+
+               cpu@0 {
+                       compatible = "mti,5KEf";
+                       device_type = "cpu";
+               };
+       };
+};
diff --git a/arch/mips/goldfish/switch.c b/arch/mips/goldfish/switch.c
new file mode 100644 (file)
index 0000000..85bddfd
--- /dev/null
@@ -0,0 +1,227 @@
+/* arch/mips/mach-goldfish/timer.c
+**
+** Copyright (C) 2007 Google, Inc.
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+**
+*/
+
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+
+enum {
+       SW_NAME_LEN     = 0x00,
+       SW_NAME_PTR     = 0x04,
+       SW_FLAGS        = 0x08,
+       SW_STATE        = 0x0c,
+       SW_INT_STATUS   = 0x10,
+       SW_INT_ENABLE   = 0x14,
+
+       SW_FLAGS_OUTPUT = 1U << 0
+};
+
+static struct class *goldfish_switch_class;
+
+struct goldfish_switch {
+       void __iomem *base;
+       int irq;
+       uint32_t state;
+       uint32_t flags;
+       struct device *cdev;
+       struct work_struct work;
+       char name[0];
+};
+
+static irqreturn_t
+goldfish_switch_interrupt(int irq, void *dev_id)
+{
+       struct goldfish_switch  *qs = dev_id;
+       uint32_t status;
+
+       status = readl(qs->base + SW_INT_STATUS);
+       if (status) {
+               qs->state = readl(qs->base + SW_STATE);
+               schedule_work(&qs->work);
+       }
+
+       return status ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static ssize_t goldfish_switch_state_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf,
+                               size_t count)
+{
+       struct goldfish_switch  *qs = dev_get_drvdata(dev);
+       uint32_t state;
+
+       if (!(qs->flags & SW_FLAGS_OUTPUT))
+               return -EPERM;
+
+       if (sscanf(buf, "%d", &state) != 1)
+               return -EINVAL;
+
+       writel(state, qs->base + SW_STATE);
+       qs->state = readl(qs->base + SW_STATE);
+       if (state != qs->state)
+               return -EINVAL;
+
+       return count;
+}
+
+static ssize_t goldfish_switch_state_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct goldfish_switch  *qs = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", qs->state);
+}
+
+static ssize_t goldfish_switch_direction_show(struct device *dev,
+                                             struct device_attribute *attr,
+                                             char *buf)
+{
+       struct goldfish_switch  *qs = dev_get_drvdata(dev);
+       return sprintf(buf, "%s\n", (qs->flags & SW_FLAGS_OUTPUT)  ? "output" : "input");
+}
+
+
+static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, goldfish_switch_state_show, goldfish_switch_state_store);
+static DEVICE_ATTR(direction, S_IRUGO, goldfish_switch_direction_show, NULL);
+
+void goldfish_switch_work(struct work_struct *work)
+{
+#if 0 /* TODO: use some other update notification */
+       struct goldfish_switch *qs = container_of(work, struct goldfish_switch, work);
+       int ret;
+       ret = sysfs_update_file(&qs->cdev->kobj, &class_device_attr_state.attr);
+#endif
+}
+
+static int goldfish_switch_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *r;
+       struct goldfish_switch *qs;
+       void __iomem *base;
+       uint32_t name_len;
+       unsigned long swdev_addr;
+       unsigned long swdev_len;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               ret = -ENODEV;
+               goto err_no_io_base;
+       }
+       swdev_addr = r->start;
+       swdev_len = resource_size(r);
+       base = ioremap(swdev_addr, swdev_len);
+       name_len = readl(base + SW_NAME_LEN);
+
+       qs = kzalloc(sizeof(*qs) + name_len + 1, GFP_KERNEL);
+       if (qs == NULL) {
+               ret = -ENOMEM;
+               goto err_qs_alloc_failed;
+       }
+       platform_set_drvdata(pdev, qs);
+       qs->base = base;
+       r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (r == NULL) {
+               ret = -ENODEV;
+               goto err_no_irq;
+       }
+       qs->irq = r->start;
+
+       writel((u32)(qs->name), base + SW_NAME_PTR);
+       qs->name[name_len] = '\0';
+       writel(0, base + SW_INT_ENABLE);
+
+       qs->flags = readl(base + SW_FLAGS);
+       qs->state = readl(base + SW_STATE);
+       INIT_WORK(&qs->work, goldfish_switch_work);
+
+       qs->cdev = device_create(goldfish_switch_class, &pdev->dev, 0,
+                                               NULL, "%s", qs->name);
+       if (unlikely(IS_ERR(qs->cdev))) {
+               ret = PTR_ERR(qs->cdev);
+               goto err_device_create_failed;
+       }
+       dev_set_drvdata(qs->cdev, qs);
+
+       ret = device_create_file(qs->cdev, &dev_attr_state);
+       if (ret)
+               goto err_device_create_file_failed;
+
+       ret = device_create_file(qs->cdev, &dev_attr_direction);
+       if (ret)
+               goto err_device_create_file_failed;
+
+       ret = request_irq(qs->irq, goldfish_switch_interrupt, IRQF_SHARED, "goldfish_switch", qs);
+       if (ret)
+               goto err_request_irq_failed;
+       writel(1, base + SW_INT_ENABLE);
+
+       return 0;
+
+
+//     free_irq(qs->irq, qs);
+err_request_irq_failed:
+err_device_create_file_failed:
+       device_unregister(qs->cdev);
+err_device_create_failed:
+err_no_irq:
+       kfree(qs);
+err_qs_alloc_failed:
+err_no_io_base:
+       printk(KERN_ERR "goldfish_switch_probe failed %d\n", ret);
+       return ret;
+}
+
+static int goldfish_switch_remove(struct platform_device *pdev)
+{
+       struct goldfish_switch *qs = platform_get_drvdata(pdev);
+       writel(0, qs->base + SW_INT_ENABLE);
+       free_irq(qs->irq, qs);
+       device_unregister(qs->cdev);
+       kfree(qs);
+       return 0;
+}
+
+static struct platform_driver goldfish_switch_driver = {
+       .probe = goldfish_switch_probe,
+       .remove = goldfish_switch_remove,
+       .driver = {
+               .name = "goldfish-switch"
+       }
+};
+
+static int __init goldfish_switch_init(void)
+{
+       goldfish_switch_class = class_create(THIS_MODULE, "switch");
+       if (IS_ERR(goldfish_switch_class))
+               return PTR_ERR(goldfish_switch_class);
+       return platform_driver_register(&goldfish_switch_driver);
+}
+
+static void goldfish_switch_exit(void)
+{
+       platform_driver_unregister(&goldfish_switch_driver);
+       class_destroy(goldfish_switch_class);
+}
+
+module_init(goldfish_switch_init);
+module_exit(goldfish_switch_exit);
+
diff --git a/arch/mips/include/asm/mach-goldfish/hardware.h b/arch/mips/include/asm/mach-goldfish/hardware.h
new file mode 100644 (file)
index 0000000..cdde417
--- /dev/null
@@ -0,0 +1,36 @@
+/* include/asm-mips/mach-goldfish/hardware.h
+**
+** Copyright (C) 2007 Google, Inc.
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+**
+*/
+
+#ifndef __ASM_MACH_GOLDFISH_HARDWARE_H
+#define __ASM_ARCH_GOLDFISH_HARDWARE_H
+
+/*
+ * Where in virtual memory the IO devices (timers, system controllers
+ * and so on)
+ */
+#define IO_SIZE                        0x00800000                 // How much?
+#define IO_START               0x00000000                 // PA of IO
+
+#define IO_ADDRESS(x) (ioremap(IO_START, IO_SIZE) + (x))
+
+/* For now... */
+#define dma_alloc_writecombine(dev, size, handle, gfp) \
+       dma_alloc_coherent(dev, size, handle, gfp)
+
+
+#define dma_free_writecombine(dev, size, cpu_addr, handle) \
+       dma_free_coherent(dev, size, cpu_addr, handle)
+
+#endif
diff --git a/arch/mips/include/asm/mach-goldfish/irq.h b/arch/mips/include/asm/mach-goldfish/irq.h
new file mode 100644 (file)
index 0000000..d211140
--- /dev/null
@@ -0,0 +1,33 @@
+/* include/asm-mips/mach-goldfish/irq.h
+**
+** Copyright (C) 2007 Google, Inc.
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+**
+*/
+
+#ifndef __ASM_MACH_GOLDFISH_IRQ_H
+#define __ASM_MACH_GOLDFISH_IRQ_H
+
+/* 0..7 MIPS CPU interrupts */
+#define MIPS_CPU_IRQ_BASE      0
+#define MIPS_CPU_IRQ_PIC       2
+#define MIPS_CPU_IRQ_FIQ       3 /* Not used? */
+#define MIPS_CPU_IRQ_COMPARE   7
+
+/* 8..39 Cascaded Goldfish PIC interrupts */
+#define GOLDFISH_IRQ_BASE      8
+#define GOLDFISH_IRQ_PBUS      1
+#define GOLDFISH_IRQ_RTC       3
+#define GOLDFISH_IRQ_TTY       4
+
+#define NR_IRQS                        40
+
+#endif
diff --git a/arch/mips/include/asm/mach-goldfish/time.h b/arch/mips/include/asm/mach-goldfish/time.h
new file mode 100644 (file)
index 0000000..d8de2b4
--- /dev/null
@@ -0,0 +1,18 @@
+/* include/asm-mips/mach-goldfish/time.h
+**
+** Copyright (C) 2008 MIPS Technologies, Inc.
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+**
+*/
+
+struct timespec;
+extern void save_time_delta(struct timespec *delta, struct timespec *rtc);
+extern void restore_time_delta(struct timespec *delta, struct timespec *rtc);
diff --git a/arch/mips/include/asm/mach-goldfish/war.h b/arch/mips/include/asm/mach-goldfish/war.h
new file mode 100644 (file)
index 0000000..e3b9820
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_GOLDFISH_WAR_H
+#define __ASM_MIPS_MACH_GOLDFISH_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR    0
+#define R4600_V1_HIT_CACHEOP_WAR       0
+#define R4600_V2_HIT_CACHEOP_WAR       0
+#define R5432_CP0_INTERRUPT_WAR                0
+#define BCM1250_M3_WAR                 0
+#define SIBYTE_1956_WAR                        0
+#define MIPS4K_ICACHE_REFILL_WAR       0
+#define MIPS_CACHE_SYNC_WAR            0
+#define TX49XX_ICACHE_INDEX_INV_WAR    0
+#define RM9000_CDEX_SMP_WAR            0
+#define ICACHE_REFILLS_WORKAROUND_WAR  0
+#define R10000_LLSC_WAR                        0
+#define MIPS34K_MISSED_ITLB_WAR                0
+
+#endif /* __ASM_MIPS_MACH_GOLDFISH_WAR_H */
index be0c62e28aaa9350523ed32827b0d9bb8211f70f..b6ea45507568864ddde8edc6b68965ed3d6e783b 100644 (file)
@@ -35,9 +35,19 @@ static int show_cpuinfo(struct seq_file *m, void *v)
         */
        if (n == 0) {
                seq_printf(m, "system type\t\t: %s\n", get_system_type());
+#ifndef CONFIG_GOLDFISH
                if (mips_get_machine_name())
                        seq_printf(m, "machine\t\t\t: %s\n",
                                   mips_get_machine_name());
+#else
+       /*
+        * This is needed by the Android init process to run
+        * target specific startup code
+        */
+               seq_printf(m, "Hardware\t\t: %s\n", mips_get_machine_name());
+               seq_printf(m, "Revison\t\t\t: %d\n", 1);
+#endif
+
        }
 
        seq_printf(m, "processor\t\t: %ld\n", n);