qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] arm: Raspberry Pi support


From: Jan Petrouš
Subject: [Qemu-devel] [PATCH] arm: Raspberry Pi support
Date: Mon, 2 Dec 2013 12:11:20 +0100


Initial commit. Added 'raspi' virtual platform and corresponding
BCM2835 devices support.

The code is (c) Gregory Estrade <address@hidden>
retrieved from Greg's out-of-tree repository on github
https://github.com/Torlus/qemu/tree/rpi
and squashed the following commits:
  4a9dcbd Timer fix (courtesy of Romain Caritey), LOG_REGISTERS disabled
          by default in property handler.
  9092a09 applied JacobL's patch on ATAGs
  02bf596 rpi: Default resolution set to 640x480
  c74ef39 rpi: Attempt to fix segfault in display update
  db76ca8 rpi: sysbus_from_qdev replaced by SYS_BUS_DEVICE
  1029033 rpi: pre-alpha USB controller emulation, fixes in VC->arm
               property interface and eMMC interrupt generation.
  48808d4 rpi: USB emulation started
  dd26108 rpi: ARM timer emulation
  527fd08 rpi: eMMC/fb enhancements, RiscOS is now booting.
  7e4c052 rpi: property chaanel, ARM1176 cp15-c12 added, framebuffer
               enhancements
  a8c161d Fixed include paths
  2f4f9fc Initial commit for Raspberry Pi support

Upstreaming code cleaning by Jan Petrous <address@hidden>.

Signed-off-by: Gregory Estrade <address@hidden>
Signed-off-by: Jan Petrous <address@hidden>
---
 hw/arm/Makefile.objs         |    5 +
 hw/arm/bcm2835_arm_control.h |  481 +++++++++++++++++++
 hw/arm/bcm2835_common.h      |   37 ++
 hw/arm/bcm2835_dma.c         |  380 +++++++++++++++
 hw/arm/bcm2835_emmc.c        |  861 ++++++++++++++++++++++++++++++++++
 hw/arm/bcm2835_fb.c          |  379 +++++++++++++++
 hw/arm/bcm2835_ic.c          |  255 ++++++++++
 hw/arm/bcm2835_mphi.c        |  190 ++++++++
 hw/arm/bcm2835_platform.h    |  230 +++++++++
 hw/arm/bcm2835_power.c       |  117 +++++
 hw/arm/bcm2835_property.c    |  413 ++++++++++++++++
 hw/arm/bcm2835_sbm.c         |  293 ++++++++++++
 hw/arm/bcm2835_st.c          |  218 +++++++++
 hw/arm/bcm2835_timer.c       |  260 +++++++++++
 hw/arm/bcm2835_todo.c        |   93 ++++
 hw/arm/bcm2835_usb.c         |  777 +++++++++++++++++++++++++++++++
 hw/arm/bcm2835_usb_regs.h    | 1061 ++++++++++++++++++++++++++++++++++++++++++
 hw/arm/bcm2835_vchiq.c       |  117 +++++
 hw/arm/raspi.c               |  361 ++++++++++++++
 19 files changed, 6528 insertions(+)
 create mode 100644 hw/arm/bcm2835_arm_control.h
 create mode 100644 hw/arm/bcm2835_common.h
 create mode 100644 hw/arm/bcm2835_dma.c
 create mode 100644 hw/arm/bcm2835_emmc.c
 create mode 100644 hw/arm/bcm2835_fb.c
 create mode 100644 hw/arm/bcm2835_ic.c
 create mode 100644 hw/arm/bcm2835_mphi.c
 create mode 100644 hw/arm/bcm2835_platform.h
 create mode 100644 hw/arm/bcm2835_power.c
 create mode 100644 hw/arm/bcm2835_property.c
 create mode 100644 hw/arm/bcm2835_sbm.c
 create mode 100644 hw/arm/bcm2835_st.c
 create mode 100644 hw/arm/bcm2835_timer.c
 create mode 100644 hw/arm/bcm2835_todo.c
 create mode 100644 hw/arm/bcm2835_usb.c
 create mode 100644 hw/arm/bcm2835_usb_regs.h
 create mode 100644 hw/arm/bcm2835_vchiq.c
 create mode 100644 hw/arm/raspi.c

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 3671b42..969304a 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -5,3 +5,8 @@ obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
 
 obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-y += omap1.o omap2.o strongarm.o
+
+obj-y += raspi.o bcm2835_ic.o bcm2835_st.o bcm2835_sbm.o bcm2835_power.o \
+                bcm2835_fb.o bcm2835_property.o bcm2835_vchiq.o \
+                bcm2835_emmc.o bcm2835_dma.o bcm2835_timer.o \
+                bcm2835_usb.o bcm2835_mphi.o bcm2835_todo.o
diff --git a/hw/arm/bcm2835_arm_control.h b/hw/arm/bcm2835_arm_control.h
new file mode 100644
index 0000000..ba9cf9c
--- /dev/null
+++ b/hw/arm/bcm2835_arm_control.h
@@ -0,0 +1,481 @@
+/*
+ *  linux/arch/arm/mach-bcm2708/arm_control.h
+ *
+ *  Copyright (C) 2010 Broadcom
+ *
+ * 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
+ */
+
+#ifndef __BCM2708_ARM_CONTROL_H
+#define __BCM2708_ARM_CONTROL_H
+
+/*
+ * Definitions and addresses for the ARM CONTROL logic
+ * This file is manually generated.
+ */
+
+#define ARM_BASE  0x7E00B000
+
+/* Basic configuration */
+#define ARM_CONTROL0  HW_REGISTER_RW(ARM_BASE+0x000)
+#define ARM_C0_SIZ128M   0x00000000
+#define ARM_C0_SIZ256M   0x00000001
+#define ARM_C0_SIZ512M   0x00000002
+#define ARM_C0_SIZ1G     0x00000003
+#define ARM_C0_BRESP0    0x00000000
+#define ARM_C0_BRESP1    0x00000004
+#define ARM_C0_BRESP2    0x00000008
+#define ARM_C0_BOOTHI    0x00000010
+#define ARM_C0_UNUSED05  0x00000020 /* free */
+#define ARM_C0_FULLPERI  0x00000040
+#define ARM_C0_UNUSED78  0x00000180 /* free */
+#define ARM_C0_JTAGMASK  0x00000E00
+#define ARM_C0_JTAGOFF   0x00000000
+#define ARM_C0_JTAGBASH  0x00000800 /* Debug on GPIO off */
+#define ARM_C0_JTAGGPIO  0x00000C00 /* Debug on GPIO on */
+#define ARM_C0_APROTMSK  0x0000F000
+#define ARM_C0_DBG0SYNC  0x00010000 /* VPU0 halt sync */
+#define ARM_C0_DBG1SYNC  0x00020000 /* VPU1 halt sync */
+#define ARM_C0_SWDBGREQ  0x00040000 /* HW debug request */
+#define ARM_C0_PASSHALT  0x00080000 /* ARM halt passed to debugger */
+#define ARM_C0_PRIO_PER  0x00F00000 /* per priority mask */
+#define ARM_C0_PRIO_L2   0x0F000000
+#define ARM_C0_PRIO_UC   0xF0000000
+
+#define ARM_C0_APROTPASS  0x0000A000 /* Translate 1:1 */
+#define ARM_C0_APROTUSER  0x00000000 /* Only user mode */
+#define ARM_C0_APROTSYST  0x0000F000 /* Only system mode */
+
+
+#define ARM_CONTROL1  HW_REGISTER_RW(ARM_BASE+0x440)
+#define ARM_C1_TIMER     0x00000001 /* re-route timer IRQ  to VC */
+#define ARM_C1_MAIL      0x00000002 /* re-route Mail IRQ   to VC */
+#define ARM_C1_BELL0     0x00000004 /* re-route Doorbell 0 to VC */
+#define ARM_C1_BELL1     0x00000008 /* re-route Doorbell 1 to VC */
+#define ARM_C1_PERSON    0x00000100 /* peripherals on */
+#define ARM_C1_REQSTOP   0x00000200 /* ASYNC bridge request stop */
+
+#define ARM_STATUS    HW_REGISTER_RW(ARM_BASE+0x444)
+#define ARM_S_ACKSTOP    0x80000000 /* Bridge stopped */
+#define ARM_S_READPEND   0x000003FF /* pending reads counter */
+#define ARM_S_WRITPEND   0x000FFC00 /* pending writes counter */
+
+#define ARM_ERRHALT   HW_REGISTER_RW(ARM_BASE+0x448)
+#define ARM_EH_PERIBURST  0x00000001 /* Burst write seen on peri bus */
+#define ARM_EH_ILLADDRS1  0x00000002 /* Address bits 25-27 error */
+#define ARM_EH_ILLADDRS2  0x00000004 /* Address bits 31-28 error */
+#define ARM_EH_VPU0HALT   0x00000008 /* VPU0 halted & in debug mode */
+#define ARM_EH_VPU1HALT   0x00000010 /* VPU1 halted & in debug mode */
+#define ARM_EH_ARMHALT    0x00000020 /* ARM in halted debug mode */
+
+#define ARM_ID_SECURE HW_REGISTER_RW(ARM_BASE+0x00C)
+#define ARM_ID        HW_REGISTER_RW(ARM_BASE+0x44C)
+#define ARM_IDVAL        0x364D5241
+
+/* Translation memory */
+#define ARM_TRANSLATE HW_REGISTER_RW(ARM_BASE+0x100)
+/* 32 locations: 0x100.. 0x17F */
+/* 32 spare means we CAN go to 64 pages.... */
+
+
+/* Interrupts */
+#define ARM_IRQ_PEND0 HW_REGISTER_RW(ARM_BASE+0x200)        /* Top IRQ bits */
+#define ARM_I0_TIMER    0x00000001 /* timer IRQ */
+#define ARM_I0_MAIL     0x00000002 /* Mail IRQ */
+#define ARM_I0_BELL0    0x00000004 /* Doorbell 0 */
+#define ARM_I0_BELL1    0x00000008 /* Doorbell 1 */
+#define ARM_I0_BANK1    0x00000100 /* Bank1 IRQ */
+#define ARM_I0_BANK2    0x00000200 /* Bank2 IRQ */
+
+#define ARM_IRQ_PEND1 HW_REGISTER_RW(ARM_BASE+0x204) /* All bank1 IRQ bits */
+/* todo: all I1_interrupt sources */
+#define ARM_IRQ_PEND2 HW_REGISTER_RW(ARM_BASE+0x208) /* All bank2 IRQ bits */
+/* todo: all I2_interrupt sources */
+
+#define ARM_IRQ_FAST  HW_REGISTER_RW(ARM_BASE+0x20C) /* FIQ control */
+#define ARM_IF_INDEX    0x0000007F     /* FIQ select */
+#define ARM_IF_ENABLE   0x00000080     /* FIQ enable */
+#define ARM_IF_VCMASK   0x0000003F     /* FIQ = (index from VC source) */
+#define ARM_IF_TIMER    0x00000040     /* FIQ = ARM timer */
+#define ARM_IF_MAIL     0x00000041     /* FIQ = ARM Mail */
+#define ARM_IF_BELL0    0x00000042     /* FIQ = ARM Doorbell 0 */
+#define ARM_IF_BELL1    0x00000043     /* FIQ = ARM Doorbell 1 */
+#define ARM_IF_VP0HALT  0x00000044     /* FIQ = VPU0 Halt seen */
+#define ARM_IF_VP1HALT  0x00000045     /* FIQ = VPU1 Halt seen */
+#define ARM_IF_ILLEGAL  0x00000046     /* FIQ = Illegal access seen */
+
+#define ARM_IRQ_ENBL1 HW_REGISTER_RW(ARM_BASE+0x210) /* Bank1 enable bits */
+#define ARM_IRQ_ENBL2 HW_REGISTER_RW(ARM_BASE+0x214) /* Bank2 enable bits */
+#define ARM_IRQ_ENBL3 HW_REGISTER_RW(ARM_BASE+0x218) /* ARM irqs enable bits */
+#define ARM_IRQ_DIBL1 HW_REGISTER_RW(ARM_BASE+0x21C) /* Bank1 disable bits */
+#define ARM_IRQ_DIBL2 HW_REGISTER_RW(ARM_BASE+0x220) /* Bank2 disable bits */
+#define ARM_IRQ_DIBL3 HW_REGISTER_RW(ARM_BASE+0x224) /* ARM irqs disable bits */
+#define ARM_IE_TIMER    0x00000001     /* Timer IRQ */
+#define ARM_IE_MAIL     0x00000002     /* Mail IRQ */
+#define ARM_IE_BELL0    0x00000004     /* Doorbell 0 */
+#define ARM_IE_BELL1    0x00000008     /* Doorbell 1 */
+#define ARM_IE_VP0HALT  0x00000010     /* VPU0 Halt */
+#define ARM_IE_VP1HALT  0x00000020     /* VPU1 Halt */
+#define ARM_IE_ILLEGAL  0x00000040     /* Illegal access seen */
+
+/* Timer */
+/* For reg. fields see sp804 spec. */
+#define ARM_T_LOAD    HW_REGISTER_RW(ARM_BASE+0x400)
+#define ARM_T_VALUE   HW_REGISTER_RW(ARM_BASE+0x404)
+#define ARM_T_CONTROL HW_REGISTER_RW(ARM_BASE+0x408)
+#define ARM_T_IRQCNTL HW_REGISTER_RW(ARM_BASE+0x40C)
+#define ARM_T_RAWIRQ  HW_REGISTER_RW(ARM_BASE+0x410)
+#define ARM_T_MSKIRQ  HW_REGISTER_RW(ARM_BASE+0x414)
+#define ARM_T_RELOAD  HW_REGISTER_RW(ARM_BASE+0x418)
+#define ARM_T_PREDIV  HW_REGISTER_RW(ARM_BASE+0x41c)
+#define ARM_T_FREECNT HW_REGISTER_RW(ARM_BASE+0x420)
+
+#define TIMER_CTRL_ONESHOT  (1 << 0)
+#define TIMER_CTRL_32BIT    (1 << 1)
+#define TIMER_CTRL_DIV1     (0 << 2)
+#define TIMER_CTRL_DIV16    (1 << 2)
+#define TIMER_CTRL_DIV256   (2 << 2)
+#define TIMER_CTRL_IE       (1 << 5)
+#define TIMER_CTRL_PERIODIC (1 << 6)
+#define TIMER_CTRL_ENABLE   (1 << 7)
+#define TIMER_CTRL_DBGHALT  (1 << 8)
+#define TIMER_CTRL_ENAFREE  (1 << 9)
+#define TIMER_CTRL_FREEDIV_SHIFT 16)
+#define TIMER_CTRL_FREEDIV_MASK  0xff
+
+/* Semaphores, Doorbells, Mailboxes */
+#define ARM_SBM_OWN0  (ARM_BASE+0x800)
+#define ARM_SBM_OWN1  (ARM_BASE+0x900)
+#define ARM_SBM_OWN2  (ARM_BASE+0xA00)
+#define ARM_SBM_OWN3  (ARM_BASE+0xB00)
+
+/* MAILBOXES
+ * Register flags are common across all
+ * owner registers. See end of this section
+ *
+ * Semaphores, Doorbells, Mailboxes Owner 0
+ *
+ */
+
+#define ARM_0_SEMS       HW_REGISTER_RW(ARM_SBM_OWN0+0x00)
+#define ARM_0_SEM0       HW_REGISTER_RW(ARM_SBM_OWN0+0x00)
+#define ARM_0_SEM1       HW_REGISTER_RW(ARM_SBM_OWN0+0x04)
+#define ARM_0_SEM2       HW_REGISTER_RW(ARM_SBM_OWN0+0x08)
+#define ARM_0_SEM3       HW_REGISTER_RW(ARM_SBM_OWN0+0x0C)
+#define ARM_0_SEM4       HW_REGISTER_RW(ARM_SBM_OWN0+0x10)
+#define ARM_0_SEM5       HW_REGISTER_RW(ARM_SBM_OWN0+0x14)
+#define ARM_0_SEM6       HW_REGISTER_RW(ARM_SBM_OWN0+0x18)
+#define ARM_0_SEM7       HW_REGISTER_RW(ARM_SBM_OWN0+0x1C)
+#define ARM_0_BELL0      HW_REGISTER_RW(ARM_SBM_OWN0+0x40)
+#define ARM_0_BELL1      HW_REGISTER_RW(ARM_SBM_OWN0+0x44)
+#define ARM_0_BELL2      HW_REGISTER_RW(ARM_SBM_OWN0+0x48)
+#define ARM_0_BELL3      HW_REGISTER_RW(ARM_SBM_OWN0+0x4C)
+/* MAILBOX 0 access in Owner 0 area */
+/* Some addresses should ONLY be used by owner 0 */
+#define ARM_0_MAIL0_WRT \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0x80)  /* .. 0x8C (4 locations) */
+#define ARM_0_MAIL0_RD \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0x80)  /* .. 0x8C (4 locs) Normal read */
+#define ARM_0_MAIL0_POL \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0x90)  /* none-pop read */
+#define ARM_0_MAIL0_SND \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0x94)  /* Sender read (only LS 2 bits) */
+#define ARM_0_MAIL0_STA \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0x98)  /* Status read */
+#define ARM_0_MAIL0_CNF \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0x9C)  /* Config read/write */
+/* MAILBOX 1 access in Owner 0 area */
+/* Owner 0 should only WRITE to this mailbox */
+#define ARM_0_MAIL1_WRT \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xA0)   /* .. 0xAC (4 locations) */
+/*#define ARM_0_MAIL1_RD \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xA0) */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_0_MAIL1_POL \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xB0) */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_0_MAIL1_SND \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xB4) */ /* DO NOT USE THIS !!!!! */
+#define ARM_0_MAIL1_STA \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xB8)   /* Status read */
+/*#define ARM_0_MAIL1_CNF \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xBC) */ /* DO NOT USE THIS !!!!! */
+/* General SEM, BELL, MAIL config/status */
+#define ARM_0_SEMCLRDBG \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xE0)  /* semaphore clear/debug register */
+#define ARM_0_BELLCLRDBG \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xE4)  /* Doorbells clear/debug register */
+#define ARM_0_ALL_IRQS \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xF8)  /* ALL interrupts */
+#define ARM_0_MY_IRQS \
+        HW_REGISTER_RW(ARM_SBM_OWN0+0xFC)  /* IRQS pending for owner 0 */
+
+/* Semaphores, Doorbells, Mailboxes Owner 1 */
+#define ARM_1_SEMS       HW_REGISTER_RW(ARM_SBM_OWN1+0x00)
+#define ARM_1_SEM0       HW_REGISTER_RW(ARM_SBM_OWN1+0x00)
+#define ARM_1_SEM1       HW_REGISTER_RW(ARM_SBM_OWN1+0x04)
+#define ARM_1_SEM2       HW_REGISTER_RW(ARM_SBM_OWN1+0x08)
+#define ARM_1_SEM3       HW_REGISTER_RW(ARM_SBM_OWN1+0x0C)
+#define ARM_1_SEM4       HW_REGISTER_RW(ARM_SBM_OWN1+0x10)
+#define ARM_1_SEM5       HW_REGISTER_RW(ARM_SBM_OWN1+0x14)
+#define ARM_1_SEM6       HW_REGISTER_RW(ARM_SBM_OWN1+0x18)
+#define ARM_1_SEM7       HW_REGISTER_RW(ARM_SBM_OWN1+0x1C)
+#define ARM_1_BELL0      HW_REGISTER_RW(ARM_SBM_OWN1+0x40)
+#define ARM_1_BELL1      HW_REGISTER_RW(ARM_SBM_OWN1+0x44)
+#define ARM_1_BELL2      HW_REGISTER_RW(ARM_SBM_OWN1+0x48)
+#define ARM_1_BELL3      HW_REGISTER_RW(ARM_SBM_OWN1+0x4C)
+/* MAILBOX 0 access in Owner 0 area */
+/* Owner 1 should only WRITE to this mailbox */
+#define ARM_1_MAIL0_WRT \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0x80)  /* .. 0x8C (4 locations) */
+/*#define ARM_1_MAIL0_RD \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0x80) */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_1_MAIL0_POL \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0x90) */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_1_MAIL0_SND \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0x94) */ /* DO NOT USE THIS !!!!! */
+#define ARM_1_MAIL0_STA \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0x98)  /* Status read */
+/*#define ARM_1_MAIL0_CNF \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0x9C) */ /* DO NOT USE THIS !!!!! */
+/* MAILBOX 1 access in Owner 0 area */
+#define ARM_1_MAIL1_WRT \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xA0)  /* .. 0xAC (4 locations) */
+#define ARM_1_MAIL1_RD \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xA0)  /* .. 0xAC (4 locs) Normal read */
+#define ARM_1_MAIL1_POL \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xB0)  /* none-pop read */
+#define ARM_1_MAIL1_SND \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xB4)  /* Sender read (only LS 2 bits) */
+#define ARM_1_MAIL1_STA \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xB8)  /* Status read */
+#define ARM_1_MAIL1_CNF \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xBC)
+/* General SEM, BELL, MAIL config/status */
+#define ARM_1_SEMCLRDBG \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xE0)  /* semaphore clear/debug register */
+#define ARM_1_BELLCLRDBG \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xE4)  /* Doorbells clear/debug register */
+#define ARM_1_MY_IRQS \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xFC)  /* IRQS pending for owner 1 */
+#define ARM_1_ALL_IRQS \
+        HW_REGISTER_RW(ARM_SBM_OWN1+0xF8)  /* ALL interrupts */
+
+/* Semaphores, Doorbells, Mailboxes Owner 2 */
+#define ARM_2_SEMS       HW_REGISTER_RW(ARM_SBM_OWN2+0x00)
+#define ARM_2_SEM0       HW_REGISTER_RW(ARM_SBM_OWN2+0x00)
+#define ARM_2_SEM1       HW_REGISTER_RW(ARM_SBM_OWN2+0x04)
+#define ARM_2_SEM2       HW_REGISTER_RW(ARM_SBM_OWN2+0x08)
+#define ARM_2_SEM3       HW_REGISTER_RW(ARM_SBM_OWN2+0x0C)
+#define ARM_2_SEM4       HW_REGISTER_RW(ARM_SBM_OWN2+0x10)
+#define ARM_2_SEM5       HW_REGISTER_RW(ARM_SBM_OWN2+0x14)
+#define ARM_2_SEM6       HW_REGISTER_RW(ARM_SBM_OWN2+0x18)
+#define ARM_2_SEM7       HW_REGISTER_RW(ARM_SBM_OWN2+0x1C)
+#define ARM_2_BELL0      HW_REGISTER_RW(ARM_SBM_OWN2+0x40)
+#define ARM_2_BELL1      HW_REGISTER_RW(ARM_SBM_OWN2+0x44)
+#define ARM_2_BELL2      HW_REGISTER_RW(ARM_SBM_OWN2+0x48)
+#define ARM_2_BELL3      HW_REGISTER_RW(ARM_SBM_OWN2+0x4C)
+/* MAILBOX 0 access in Owner 2 area */
+/* Owner 2 should only WRITE to this mailbox */
+#define ARM_2_MAIL0_WRT \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0x80)   /* .. 0x8C (4 locations) */
+/*#define ARM_2_MAIL0_RD \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0x80)  */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_2_MAIL0_POL \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0x90)  */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_2_MAIL0_SND \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0x94)  */ /* DO NOT USE THIS !!!!! */
+#define ARM_2_MAIL0_STA \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0x98)   /* Status read */
+/*#define ARM_2_MAIL0_CNF \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0x9C)  */ /* DO NOT USE THIS !!!!! */
+/* MAILBOX 1 access in Owner 2 area */
+/* Owner 2 should only WRITE to this mailbox */
+#define ARM_2_MAIL1_WRT \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xA0)   /* .. 0xAC (4 locations) */
+/*#define ARM_2_MAIL1_RD \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xA0) */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_2_MAIL1_POL \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xB0) */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_2_MAIL1_SND \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xB4) */ /* DO NOT USE THIS !!!!! */
+#define ARM_2_MAIL1_STA \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xB8)   /* Status read */
+/*#define ARM_2_MAIL1_CNF \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xBC) */ /* DO NOT USE THIS !!!!! */
+/* General SEM, BELL, MAIL config/status */
+#define ARM_2_SEMCLRDBG \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xE0)  /* semaphore clear/debug register */
+#define ARM_2_BELLCLRDBG \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xE4)  /* Doorbells clear/debug register */
+#define ARM_2_MY_IRQS \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xFC)  /* IRQS pending for owner 2 */
+#define ARM_2_ALL_IRQS \
+        HW_REGISTER_RW(ARM_SBM_OWN2+0xF8)  /* ALL interrupts */
+
+/* Semaphores, Doorbells, Mailboxes Owner 3 */
+#define ARM_3_SEMS       HW_REGISTER_RW(ARM_SBM_OWN3+0x00)
+#define ARM_3_SEM0       HW_REGISTER_RW(ARM_SBM_OWN3+0x00)
+#define ARM_3_SEM1       HW_REGISTER_RW(ARM_SBM_OWN3+0x04)
+#define ARM_3_SEM2       HW_REGISTER_RW(ARM_SBM_OWN3+0x08)
+#define ARM_3_SEM3       HW_REGISTER_RW(ARM_SBM_OWN3+0x0C)
+#define ARM_3_SEM4       HW_REGISTER_RW(ARM_SBM_OWN3+0x10)
+#define ARM_3_SEM5       HW_REGISTER_RW(ARM_SBM_OWN3+0x14)
+#define ARM_3_SEM6       HW_REGISTER_RW(ARM_SBM_OWN3+0x18)
+#define ARM_3_SEM7       HW_REGISTER_RW(ARM_SBM_OWN3+0x1C)
+#define ARM_3_BELL0      HW_REGISTER_RW(ARM_SBM_OWN3+0x40)
+#define ARM_3_BELL1      HW_REGISTER_RW(ARM_SBM_OWN3+0x44)
+#define ARM_3_BELL2      HW_REGISTER_RW(ARM_SBM_OWN3+0x48)
+#define ARM_3_BELL3      HW_REGISTER_RW(ARM_SBM_OWN3+0x4C)
+/* MAILBOX 0 access in Owner 3 area */
+/* Owner 3 should only WRITE to this mailbox */
+#define ARM_3_MAIL0_WRT \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0x80)   /* .. 0x8C (4 locations) */
+/*#define ARM_3_MAIL0_RD \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0x80)  */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_3_MAIL0_POL \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0x90)  */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_3_MAIL0_SND \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0x94)  */ /* DO NOT USE THIS !!!!! */
+#define ARM_3_MAIL0_STA \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0x98)    /* Status read */
+/*#define ARM_3_MAIL0_CNF \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0x9C)  */ /* DO NOT USE THIS !!!!! */
+/* MAILBOX 1 access in Owner 3 area */
+/* Owner 3 should only WRITE to this mailbox */
+#define ARM_3_MAIL1_WRT \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xA0)   /* .. 0xAC (4 locations) */
+/*#define ARM_3_MAIL1_RD \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xA0) */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_3_MAIL1_POL \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xB0) */ /* DO NOT USE THIS !!!!! */
+/*#define ARM_3_MAIL1_SND \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xB4) */ /* DO NOT USE THIS !!!!! */
+#define ARM_3_MAIL1_STA \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xB8)   /* Status read */
+/*#define ARM_3_MAIL1_CNF \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xBC) */ /* DO NOT USE THIS !!!!! */
+/* General SEM, BELL, MAIL config/status */
+#define ARM_3_SEMCLRDBG \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xE0)  /* semaphore clear/debug register */
+#define ARM_3_BELLCLRDBG \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xE4)  /* Doorbells clear/debug register */
+#define ARM_3_MY_IRQS \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xFC)  /* IRQS pending for owner 3 */
+#define ARM_3_ALL_IRQS \
+        HW_REGISTER_RW(ARM_SBM_OWN3+0xF8)  /* ALL interrupts */
+
+/*  Mailbox flags. Valid for all owners */
+
+/* Mailbox status register (...0x98) */
+#define ARM_MS_FULL       0x80000000
+#define ARM_MS_EMPTY      0x40000000
+#define ARM_MS_LEVEL      0x400000FF /* Max. value depends on mailbox depth */
+
+/* MAILBOX config/status register (...0x9C) */
+/* ANY write to this register clears the error bits! */
+#define ARM_MC_IHAVEDATAIRQEN    0x00000001 /* mbox irq enable:  has data */
+#define ARM_MC_IHAVESPACEIRQEN   0x00000002 /* mbox irq enable:  has space */
+#define ARM_MC_OPPISEMPTYIRQEN   0x00000004 /* mbox irq enable: Opp is empty */
+#define ARM_MC_MAIL_CLEAR        0x00000008 /* mbox clear write 1, then  0 */
+#define ARM_MC_IHAVEDATAIRQPEND  0x00000010 /* mbox irq pending:  has space */
+#define ARM_MC_IHAVESPACEIRQPEND 0x00000020 /* mbox irq pending: Opp is empty */
+#define ARM_MC_OPPISEMPTYIRQPEND 0x00000040 /* mbox irq pending */
+/* Bit 7 is unused */
+#define ARM_MC_ERRNOOWN   0x00000100 /* error : none owner read from mailbox */
+#define ARM_MC_ERROVERFLW 0x00000200 /* error : write to fill mailbox */
+#define ARM_MC_ERRUNDRFLW 0x00000400 /* error : read from empty mailbox */
+
+/* Semaphore clear/debug register (...0xE0) */
+#define ARM_SD_OWN0      0x00000003  /* Owner of sem 0 */
+#define ARM_SD_OWN1      0x0000000C  /* Owner of sem 1 */
+#define ARM_SD_OWN2      0x00000030  /* Owner of sem 2 */
+#define ARM_SD_OWN3      0x000000C0  /* Owner of sem 3 */
+#define ARM_SD_OWN4      0x00000300  /* Owner of sem 4 */
+#define ARM_SD_OWN5      0x00000C00  /* Owner of sem 5 */
+#define ARM_SD_OWN6      0x00003000  /* Owner of sem 6 */
+#define ARM_SD_OWN7      0x0000C000  /* Owner of sem 7 */
+#define ARM_SD_SEM0      0x00010000  /* Status of sem 0 */
+#define ARM_SD_SEM1      0x00020000  /* Status of sem 1 */
+#define ARM_SD_SEM2      0x00040000  /* Status of sem 2 */
+#define ARM_SD_SEM3      0x00080000  /* Status of sem 3 */
+#define ARM_SD_SEM4      0x00100000  /* Status of sem 4 */
+#define ARM_SD_SEM5      0x00200000  /* Status of sem 5 */
+#define ARM_SD_SEM6      0x00400000  /* Status of sem 6 */
+#define ARM_SD_SEM7      0x00800000  /* Status of sem 7 */
+
+/* Doorbells clear/debug register (...0xE4) */
+#define ARM_BD_OWN0      0x00000003  /* Owner of doorbell 0 */
+#define ARM_BD_OWN1      0x0000000C  /* Owner of doorbell 1 */
+#define ARM_BD_OWN2      0x00000030  /* Owner of doorbell 2 */
+#define ARM_BD_OWN3      0x000000C0  /* Owner of doorbell 3 */
+#define ARM_BD_BELL0     0x00000100  /* Status of doorbell 0 */
+#define ARM_BD_BELL1     0x00000200  /* Status of doorbell 1 */
+#define ARM_BD_BELL2     0x00000400  /* Status of doorbell 2 */
+#define ARM_BD_BELL3     0x00000800  /* Status of doorbell 3 */
+
+/* MY IRQS register (...0xF8) */
+#define ARM_MYIRQ_BELL   0x00000001  /* This owner has a doorbell IRQ */
+#define ARM_MYIRQ_MAIL   0x00000002  /* This owner has a mailbox  IRQ */
+
+/* ALL IRQS register (...0xF8) */
+#define ARM_AIS_BELL0 0x00000001  /* Doorbell 0 IRQ pending */
+#define ARM_AIS_BELL1 0x00000002  /* Doorbell 1 IRQ pending */
+#define ARM_AIS_BELL2 0x00000004  /* Doorbell 2 IRQ pending */
+#define ARM_AIS_BELL3 0x00000008  /* Doorbell 3 IRQ pending */
+#define ARM_AIS0_HAVEDATA 0x00000010  /* MAIL 0 has data IRQ pending */
+#define ARM_AIS0_HAVESPAC 0x00000020  /* MAIL 0 has space IRQ pending */
+#define ARM_AIS0_OPPEMPTY 0x00000040  /* MAIL 0 opposite is empty IRQ */
+#define ARM_AIS1_HAVEDATA 0x00000080  /* MAIL 1 has data IRQ pending */
+#define ARM_AIS1_HAVESPAC 0x00000100  /* MAIL 1 has space IRQ pending */
+#define ARM_AIS1_OPPEMPTY 0x00000200  /* MAIL 1 opposite is empty IRQ */
+/* Note   that bell-0, bell-1 and MAIL0 IRQ go only to the ARM */
+/* Whilst that bell-2, bell-3 and MAIL1 IRQ go only to the VC */
+/* */
+/* ARM JTAG BASH */
+/* */
+#define AJB_BASE 0x7e2000c0
+
+#define AJBCONF HW_REGISTER_RW(AJB_BASE+0x00)
+#define   AJB_BITS0    0x000000
+#define   AJB_BITS4    0x000004
+#define   AJB_BITS8    0x000008
+#define   AJB_BITS12   0x00000C
+#define   AJB_BITS16   0x000010
+#define   AJB_BITS20   0x000014
+#define   AJB_BITS24   0x000018
+#define   AJB_BITS28   0x00001C
+#define   AJB_BITS32   0x000020
+#define   AJB_BITS34   0x000022
+#define   AJB_OUT_MS   0x000040
+#define   AJB_OUT_LS   0x000000
+#define   AJB_INV_CLK  0x000080
+#define   AJB_D0_RISE  0x000100
+#define   AJB_D0_FALL  0x000000
+#define   AJB_D1_RISE  0x000200
+#define   AJB_D1_FALL  0x000000
+#define   AJB_IN_RISE  0x000400
+#define   AJB_IN_FALL  0x000000
+#define   AJB_ENABLE   0x000800
+#define   AJB_HOLD0    0x000000
+#define   AJB_HOLD1    0x001000
+#define   AJB_HOLD2    0x002000
+#define   AJB_HOLD3    0x003000
+#define   AJB_RESETN   0x004000
+#define   AJB_CLKSHFT  16
+#define   AJB_BUSY     0x80000000
+#define AJBTMS HW_REGISTER_RW(AJB_BASE+0x04)
+#define AJBTDI HW_REGISTER_RW(AJB_BASE+0x08)
+#define AJBTDO HW_REGISTER_RW(AJB_BASE+0x0c)
+
+#endif
diff --git a/hw/arm/bcm2835_common.h b/hw/arm/bcm2835_common.h
new file mode 100644
index 0000000..dc91fd6
--- /dev/null
+++ b/hw/arm/bcm2835_common.h
@@ -0,0 +1,37 @@
+#ifndef __BCM2835_COMMON_H
+#define __BCM2835_COMMON_H
+
+#include "bcm2835_platform.h"
+
+#define VCRAM_SIZE (0x4000000)
+extern hwaddr bcm2835_vcram_base;
+
+/* Constants shared with the ARM identifying separate mailbox channels */
+#define MBOX_CHAN_POWER    0 /* for use by the power management interface */
+#define MBOX_CHAN_FB       1 /* for use by the frame buffer */
+#define MBOX_CHAN_VCHIQ    3 /* for use by the VCHIQ interface */
+#define MBOX_CHAN_PROPERTY 8 /* for use by the property channel */
+#define MBOX_CHAN_COUNT    9
+
+#define MBOX_SIZE       32
+#define MBOX_INVALID_DATA   0x0f
+
+#define BCM2835_FB_OFFSET 0x00100000
+
+typedef struct {
+    QemuConsole *con;
+    int invalidate;
+    int lock;
+
+    uint32_t xres, yres;
+    uint32_t xres_virtual, yres_virtual;
+    uint32_t xoffset, yoffset;
+    uint32_t bpp;
+    uint32_t base, pitch, size;
+
+    uint32_t pixo, alpha;
+} bcm2835_fb_type;
+
+extern bcm2835_fb_type bcm2835_fb;
+
+#endif
diff --git a/hw/arm/bcm2835_dma.c b/hw/arm/bcm2835_dma.c
new file mode 100644
index 0000000..269af62
--- /dev/null
+++ b/hw/arm/bcm2835_dma.c
@@ -0,0 +1,380 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+
+/* DMA CS Control and Status bits */
+#define BCM2708_DMA_ACTIVE      (1 << 0)
+#define BCM2708_DMA_INT         (1 << 2)
+#define BCM2708_DMA_ISPAUSED    (1 << 4)  /* Pause requested or not active */
+#define BCM2708_DMA_ISHELD      (1 << 5)  /* Is held by DREQ flow control */
+#define BCM2708_DMA_ERR         (1 << 8)
+#define BCM2708_DMA_ABORT       (1 << 30) /* stop current CB, go to next, WO */
+#define BCM2708_DMA_RESET       (1 << 31) /* WO, self clearing */
+
+#define BCM2708_DMA_END         (1 << 1) /* GE */
+
+/* DMA control block "info" field bits */
+#define BCM2708_DMA_INT_EN      (1 << 0)
+#define BCM2708_DMA_TDMODE      (1 << 1)
+#define BCM2708_DMA_WAIT_RESP   (1 << 3)
+#define BCM2708_DMA_D_INC       (1 << 4)
+#define BCM2708_DMA_D_WIDTH     (1 << 5)
+#define BCM2708_DMA_D_DREQ      (1 << 6)
+#define BCM2708_DMA_S_INC       (1 << 8)
+#define BCM2708_DMA_S_WIDTH     (1 << 9)
+#define BCM2708_DMA_S_DREQ      (1 << 10)
+
+#define BCM2708_DMA_BURST(x)    (((x)&0xf) << 12)
+#define BCM2708_DMA_PER_MAP(x)  ((x) << 16)
+#define BCM2708_DMA_WAITS(x)    (((x)&0x1f) << 21)
+
+#define BCM2708_DMA_DREQ_EMMC   11
+#define BCM2708_DMA_DREQ_SDHOST 13
+
+#define BCM2708_DMA_CS          0x00 /* Control and Status */
+#define BCM2708_DMA_ADDR        0x04
+/* the current control block appears in the following registers - read only */
+#define BCM2708_DMA_INFO        0x08
+#define BCM2708_DMA_NEXTCB      0x1C
+#define BCM2708_DMA_DEBUG       0x20
+
+#define BCM2708_DMA4_CS         (BCM2708_DMA_CHAN(4)+BCM2708_DMA_CS)
+#define BCM2708_DMA4_ADDR       (BCM2708_DMA_CHAN(4)+BCM2708_DMA_ADDR)
+
+#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w))
+
+
+/* #define LOG_REG_ACCESS */
+
+typedef struct {
+    uint32_t cs;
+    uint32_t conblk_ad;
+    uint32_t ti;
+    uint32_t source_ad;
+    uint32_t dest_ad;
+    uint32_t txfr_len;
+    uint32_t stride;
+    uint32_t nextconbk;
+    uint32_t debug;
+
+    qemu_irq irq;
+} dmachan;
+
+#define TYPE_BCM2835_DMA "bcm2835_dma"
+#define BCM2835_DMA(obj) \
+        OBJECT_CHECK(bcm2835_dma_state, (obj), TYPE_BCM2835_DMA)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem0_14;
+    MemoryRegion iomem15;
+
+    dmachan chan[16];
+    uint32_t int_status;
+    uint32_t enable;
+
+} bcm2835_dma_state;
+
+
+static void bcm2835_dma_update(bcm2835_dma_state *s, int c)
+{
+    dmachan *ch = &s->chan[c];
+    uint32_t data;
+
+    if (!(s->enable & (1 << c))) {
+        return;
+    }
+
+    while ((s->enable & (1 << c)) && (ch->conblk_ad != 0)) {
+        /* CB fetch */
+        ch->ti = ldl_phys(ch->conblk_ad);
+        ch->source_ad = ldl_phys(ch->conblk_ad + 4);
+        ch->dest_ad = ldl_phys(ch->conblk_ad + 8);
+        ch->txfr_len = ldl_phys(ch->conblk_ad + 12);
+        ch->stride = ldl_phys(ch->conblk_ad + 16);
+        ch->nextconbk = ldl_phys(ch->conblk_ad + 20);
+
+        assert(!(ch->ti & BCM2708_DMA_TDMODE));
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_dma[%d]: BEGIN src="" dst=%08x len=%08x\n", c,
+        ch->source_ad, ch->dest_ad, ch->txfr_len);
+#endif
+
+        while (ch->txfr_len != 0) {
+            data = "">
+            if (ch->ti & (1 << 11)) {
+                /* Ignore reads */
+            } else {
+                data = "">
+            }
+            if (ch->ti & BCM2708_DMA_S_INC) {
+                ch->source_ad += 4;
+            }
+
+            if (ch->ti & (1 << 7)) {
+                /* Ignore writes */
+            } else {
+                stl_phys(ch->dest_ad, data);
+            }
+            if (ch->ti & BCM2708_DMA_D_INC) {
+                ch->dest_ad += 4;
+            }
+            ch->txfr_len -= 4;
+        }
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_dma[%d]: END src="" dst=%08x len=%08x\n", c,
+        ch->source_ad, ch->dest_ad, ch->txfr_len);
+#endif
+
+        ch->cs |= BCM2708_DMA_END;
+        if (ch->ti & BCM2708_DMA_INT_EN) {
+            ch->cs |= BCM2708_DMA_INT;
+            s->int_status |= (1 << c);
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_dma[%d]: IRQ\n", c);
+#endif
+            qemu_set_irq(ch->irq, 1);
+        }
+
+        /* Process next CB */
+        ch->conblk_ad = ch->nextconbk;
+    }
+    ch->cs &= ~BCM2708_DMA_ACTIVE;
+}
+
+static uint64_t bcm2835_dma_read(bcm2835_dma_state *s, hwaddr offset,
+    unsigned size, int c)
+{
+    dmachan *ch = &s->chan[c];
+    uint32_t res = 0;
+
+    assert(size == 4);
+
+    switch (offset) {
+    case 0x0:
+        res = ch->cs;
+        break;
+    case 0x4:
+        res = ch->conblk_ad;
+        break;
+    case 0x8:
+        res = ch->ti;
+        break;
+    case 0xc:
+        res = ch->source_ad;
+        break;
+    case 0x10:
+        res = ch->dest_ad;
+        break;
+    case 0x14:
+        res = ch->txfr_len;
+        break;
+    case 0x18:
+        res = ch->stride;
+        break;
+    case 0x1c:
+        res = ch->nextconbk;
+        break;
+    case 0x20:
+        res = ch->debug;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_dma_read: Bad offset %x\n", (int)offset);
+        break;
+    }
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_dma[%d]: read(%x) %08x\n", c, (int)offset, res);
+#endif
+
+    return res;
+}
+
+static void bcm2835_dma_write(bcm2835_dma_state *s, hwaddr offset,
+    uint64_t value, unsigned size, int c)
+{
+    dmachan *ch = &s->chan[c];
+    uint32_t oldcs = ch->cs;
+
+    assert(size == 4);
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_dma[%d]: write(%x) %08x\n", c,
+        (int)offset, (uint32_t)value);
+#endif
+
+    switch (offset) {
+    case 0x0:
+        if (value & BCM2708_DMA_RESET) {
+            ch->cs |= BCM2708_DMA_RESET;
+        }
+        if (value & BCM2708_DMA_ABORT) {
+            ch->cs |= BCM2708_DMA_ABORT;
+        }
+        if (value & BCM2708_DMA_END) {
+            ch->cs &= ~BCM2708_DMA_END;
+        }
+        if (value & BCM2708_DMA_INT) {
+            ch->cs &= ~BCM2708_DMA_INT;
+            s->int_status &= ~(1 << c);
+            qemu_set_irq(ch->irq, 0);
+        }
+        ch->cs &= ~0x30ff0001;
+        ch->cs |= (value & 0x30ff0001);
+        if (!(oldcs & BCM2708_DMA_ACTIVE) && (ch->cs & BCM2708_DMA_ACTIVE)) {
+            bcm2835_dma_update(s, c);
+        }
+        break;
+    case 0x4:
+        ch->conblk_ad = value;
+        break;
+    case 0x8:
+        ch->ti = value;
+        break;
+    case 0xc:
+        ch->source_ad = value;
+        break;
+    case 0x10:
+        ch->dest_ad = value;
+        break;
+    case 0x14:
+        ch->txfr_len = value;
+        break;
+    case 0x18:
+        ch->stride = value;
+        break;
+    case 0x1c:
+        ch->nextconbk = value;
+        break;
+    case 0x20:
+        ch->debug = value;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_dma_write: Bad offset %x\n", (int)offset);
+        break;
+    }
+}
+
+/* ==================================================================== */
+
+static uint64_t bcm2835_dma0_14_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_dma_state *s = (bcm2835_dma_state *)opaque;
+    if (offset == 0xfe0) {
+        return s->int_status;
+    }
+    if (offset == 0xff0) {
+        return s->enable;
+    }
+    return bcm2835_dma_read(s, (offset & 0xff),
+        size, (offset >> 8) & 0xf);
+}
+
+static uint64_t bcm2835_dma15_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    return bcm2835_dma_read((bcm2835_dma_state *)opaque, (offset & 0xff),
+        size, 15);
+}
+
+static void bcm2835_dma0_14_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+    bcm2835_dma_state *s = (bcm2835_dma_state *)opaque;
+    if (offset == 0xfe0) {
+        return;
+    }
+    if (offset == 0xff0) {
+        s->enable = (value & 0xffff);
+        return;
+    }
+    bcm2835_dma_write(s, (offset & 0xff),
+        value, size, (offset >> 8) & 0xf);
+}
+
+static void bcm2835_dma15_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+    bcm2835_dma_write((bcm2835_dma_state *)opaque, (offset & 0xff),
+        value, size, 15);
+}
+
+
+static const MemoryRegionOps bcm2835_dma0_14_ops = {
+    .read = bcm2835_dma0_14_read,
+    .write = bcm2835_dma0_14_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps bcm2835_dma15_ops = {
+    .read = bcm2835_dma15_read,
+    .write = bcm2835_dma15_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_bcm2835_dma = {
+    .name = "bcm2835_dma",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_dma_init(SysBusDevice *sbd)
+{
+    int n;
+    /* bcm2835_dma_state *s = FROM_SYSBUS(bcm2835_dma_state, dev); */
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_dma_state *s = BCM2835_DMA(dev);
+
+    s->enable = 0xffff;
+    s->int_status = 0;
+    for (n = 0; n < 16; n++) {
+        s->chan[n].cs = 0;
+        s->chan[n].conblk_ad = 0;
+        sysbus_init_irq(sbd, &s->chan[n].irq);
+    }
+
+    memory_region_init_io(&s->iomem0_14, OBJECT(s), &bcm2835_dma0_14_ops, s,
+        "bcm2835_dma0_14", 0xf00);
+    sysbus_init_mmio(sbd, &s->iomem0_14);
+    memory_region_init_io(&s->iomem15, OBJECT(s), &bcm2835_dma15_ops, s,
+        "bcm2835_dma15", 0x100);
+    sysbus_init_mmio(sbd, &s->iomem15);
+
+    vmstate_register(dev, -1, &vmstate_bcm2835_dma, s);
+
+    return 0;
+}
+
+static void bcm2835_dma_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = bcm2835_dma_init;
+}
+
+static TypeInfo bcm2835_dma_info = {
+    .name          = "bcm2835_dma",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_dma_state),
+    .class_init    = bcm2835_dma_class_init,
+};
+
+static void bcm2835_dma_register_types(void)
+{
+    type_register_static(&bcm2835_dma_info);
+}
+
+type_init(bcm2835_dma_register_types)
diff --git a/hw/arm/bcm2835_emmc.c b/hw/arm/bcm2835_emmc.c
new file mode 100644
index 0000000..d22520c
--- /dev/null
+++ b/hw/arm/bcm2835_emmc.c
@@ -0,0 +1,861 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+#include "qemu/timer.h"
+#include "sysemu/blockdev.h"
+#include "hw/sd.h"
+
+/*
+ * Controller registers
+ */
+
+#define SDHCI_DMA_ADDRESS   0x00
+#define SDHCI_ARGUMENT2     SDHCI_DMA_ADDRESS
+
+#define SDHCI_BLOCK_SIZE    0x04
+#define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
+
+#define SDHCI_BLOCK_COUNT   0x06
+
+#define SDHCI_ARGUMENT      0x08
+
+#define SDHCI_TRANSFER_MODE 0x0C
+#define  SDHCI_TRNS_DMA     0x01
+#define  SDHCI_TRNS_BLK_CNT_EN  0x02
+#define  SDHCI_TRNS_AUTO_CMD12  0x04
+#define  SDHCI_TRNS_AUTO_CMD23  0x08
+#define  SDHCI_TRNS_READ    0x10
+#define  SDHCI_TRNS_MULTI   0x20
+
+#define SDHCI_COMMAND       0x0E
+#define  SDHCI_CMD_RESP_MASK    0x03
+#define  SDHCI_CMD_CRC      0x08
+#define  SDHCI_CMD_INDEX    0x10
+#define  SDHCI_CMD_DATA     0x20
+#define  SDHCI_CMD_ABORTCMD 0xC0
+
+#define  SDHCI_CMD_RESP_NONE    0x00
+#define  SDHCI_CMD_RESP_LONG    0x01
+#define  SDHCI_CMD_RESP_SHORT   0x02
+#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03
+
+#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
+#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f)
+
+#define SDHCI_RESPONSE      0x10
+
+#define SDHCI_BUFFER        0x20
+
+#define SDHCI_PRESENT_STATE 0x24
+#define  SDHCI_CMD_INHIBIT  0x00000001
+#define  SDHCI_DATA_INHIBIT 0x00000002
+#define  SDHCI_DOING_WRITE  0x00000100
+#define  SDHCI_DOING_READ   0x00000200
+#define  SDHCI_SPACE_AVAILABLE  0x00000400
+#define  SDHCI_DATA_AVAILABLE   0x00000800
+#define  SDHCI_CARD_PRESENT 0x00010000
+#define  SDHCI_WRITE_PROTECT    0x00080000
+#define  SDHCI_DATA_LVL_MASK    0x00F00000
+#define   SDHCI_DATA_LVL_SHIFT  20
+
+#define SDHCI_HOST_CONTROL  0x28
+#define  SDHCI_CTRL_LED     0x01
+#define  SDHCI_CTRL_4BITBUS 0x02
+#define  SDHCI_CTRL_HISPD   0x04
+#define  SDHCI_CTRL_DMA_MASK    0x18
+#define   SDHCI_CTRL_SDMA   0x00
+#define   SDHCI_CTRL_ADMA1  0x08
+#define   SDHCI_CTRL_ADMA32 0x10
+#define   SDHCI_CTRL_ADMA64 0x18
+#define   SDHCI_CTRL_8BITBUS    0x20
+
+#define SDHCI_POWER_CONTROL 0x29
+#define  SDHCI_POWER_ON     0x01
+#define  SDHCI_POWER_180    0x0A
+#define  SDHCI_POWER_300    0x0C
+#define  SDHCI_POWER_330    0x0E
+
+#define SDHCI_BLOCK_GAP_CONTROL 0x2A
+
+#define SDHCI_WAKE_UP_CONTROL   0x2B
+#define  SDHCI_WAKE_ON_INT  0x01
+#define  SDHCI_WAKE_ON_INSERT   0x02
+#define  SDHCI_WAKE_ON_REMOVE   0x04
+
+#define SDHCI_CLOCK_CONTROL 0x2C
+#define  SDHCI_DIVIDER_SHIFT    8
+#define  SDHCI_DIVIDER_HI_SHIFT 6
+#define  SDHCI_DIV_MASK 0xFF
+#define  SDHCI_DIV_MASK_LEN 8
+#define  SDHCI_DIV_HI_MASK  0x300
+#define  SDHCI_PROG_CLOCK_MODE  0x0020
+#define  SDHCI_CLOCK_CARD_EN    0x0004
+#define  SDHCI_CLOCK_INT_STABLE 0x0002
+#define  SDHCI_CLOCK_INT_EN 0x0001
+
+#define SDHCI_TIMEOUT_CONTROL   0x2E
+
+#define SDHCI_SOFTWARE_RESET    0x2F
+#define  SDHCI_RESET_ALL    0x01
+#define  SDHCI_RESET_CMD    0x02
+#define  SDHCI_RESET_DATA   0x04
+
+#define SDHCI_INT_STATUS    0x30
+#define SDHCI_INT_ENABLE    0x34
+#define SDHCI_SIGNAL_ENABLE 0x38
+#define  SDHCI_INT_RESPONSE 0x00000001
+#define  SDHCI_INT_DATA_END 0x00000002
+#define  SDHCI_INT_DMA_END  0x00000008
+#define  SDHCI_INT_SPACE_AVAIL  0x00000010
+#define  SDHCI_INT_DATA_AVAIL   0x00000020
+#define  SDHCI_INT_CARD_INSERT  0x00000040
+#define  SDHCI_INT_CARD_REMOVE  0x00000080
+#define  SDHCI_INT_CARD_INT 0x00000100
+#define  SDHCI_INT_ERROR    0x00008000
+#define  SDHCI_INT_TIMEOUT  0x00010000
+#define  SDHCI_INT_CRC      0x00020000
+#define  SDHCI_INT_END_BIT  0x00040000
+#define  SDHCI_INT_INDEX    0x00080000
+#define  SDHCI_INT_DATA_TIMEOUT 0x00100000
+#define  SDHCI_INT_DATA_CRC 0x00200000
+#define  SDHCI_INT_DATA_END_BIT 0x00400000
+#define  SDHCI_INT_BUS_POWER    0x00800000
+#define  SDHCI_INT_ACMD12ERR    0x01000000
+#define  SDHCI_INT_ADMA_ERROR   0x02000000
+
+#define  SDHCI_INT_NORMAL_MASK  0x00007FFF
+#define  SDHCI_INT_ERROR_MASK   0xFFFF8000
+
+#define  SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
+        SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
+#define  SDHCI_INT_DATA_MASK    (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
+        SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
+        SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
+        SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
+#define SDHCI_INT_ALL_MASK  ((unsigned int)-1)
+
+#define SDHCI_ACMD12_ERR    0x3C
+
+#define SDHCI_HOST_CONTROL2     0x3E
+#define  SDHCI_CTRL_UHS_MASK        0x0007
+#define   SDHCI_CTRL_UHS_SDR12      0x0000
+#define   SDHCI_CTRL_UHS_SDR25      0x0001
+#define   SDHCI_CTRL_UHS_SDR50      0x0002
+#define   SDHCI_CTRL_UHS_SDR104     0x0003
+#define   SDHCI_CTRL_UHS_DDR50      0x0004
+#define  SDHCI_CTRL_VDD_180     0x0008
+#define  SDHCI_CTRL_DRV_TYPE_MASK   0x0030
+#define   SDHCI_CTRL_DRV_TYPE_B     0x0000
+#define   SDHCI_CTRL_DRV_TYPE_A     0x0010
+#define   SDHCI_CTRL_DRV_TYPE_C     0x0020
+#define   SDHCI_CTRL_DRV_TYPE_D     0x0030
+#define  SDHCI_CTRL_EXEC_TUNING     0x0040
+#define  SDHCI_CTRL_TUNED_CLK       0x0080
+#define  SDHCI_CTRL_PRESET_VAL_ENABLE   0x8000
+
+#define SDHCI_CAPABILITIES  0x40
+#define  SDHCI_TIMEOUT_CLK_MASK 0x0000003F
+#define  SDHCI_TIMEOUT_CLK_SHIFT 0
+#define  SDHCI_TIMEOUT_CLK_UNIT 0x00000080
+#define  SDHCI_CLOCK_BASE_MASK  0x00003F00
+#define  SDHCI_CLOCK_V3_BASE_MASK   0x0000FF00
+#define  SDHCI_CLOCK_BASE_SHIFT 8
+#define  SDHCI_MAX_BLOCK_MASK   0x00030000
+#define  SDHCI_MAX_BLOCK_SHIFT  16
+#define  SDHCI_CAN_DO_8BIT  0x00040000
+#define  SDHCI_CAN_DO_ADMA2 0x00080000
+#define  SDHCI_CAN_DO_ADMA1 0x00100000
+#define  SDHCI_CAN_DO_HISPD 0x00200000
+#define  SDHCI_CAN_DO_SDMA  0x00400000
+#define  SDHCI_CAN_VDD_330  0x01000000
+#define  SDHCI_CAN_VDD_300  0x02000000
+#define  SDHCI_CAN_VDD_180  0x04000000
+#define  SDHCI_CAN_64BIT    0x10000000
+
+#define  SDHCI_SUPPORT_SDR50    0x00000001
+#define  SDHCI_SUPPORT_SDR104   0x00000002
+#define  SDHCI_SUPPORT_DDR50    0x00000004
+#define  SDHCI_DRIVER_TYPE_A    0x00000010
+#define  SDHCI_DRIVER_TYPE_C    0x00000020
+#define  SDHCI_DRIVER_TYPE_D    0x00000040
+#define  SDHCI_RETUNING_TIMER_COUNT_MASK    0x00000F00
+#define  SDHCI_RETUNING_TIMER_COUNT_SHIFT   8
+#define  SDHCI_USE_SDR50_TUNING         0x00002000
+#define  SDHCI_RETUNING_MODE_MASK       0x0000C000
+#define  SDHCI_RETUNING_MODE_SHIFT      14
+#define  SDHCI_CLOCK_MUL_MASK   0x00FF0000
+#define  SDHCI_CLOCK_MUL_SHIFT  16
+
+#define SDHCI_CAPABILITIES_1    0x44
+
+#define SDHCI_MAX_CURRENT       0x48
+#define  SDHCI_MAX_CURRENT_330_MASK 0x0000FF
+#define  SDHCI_MAX_CURRENT_330_SHIFT    0
+#define  SDHCI_MAX_CURRENT_300_MASK 0x00FF00
+#define  SDHCI_MAX_CURRENT_300_SHIFT    8
+#define  SDHCI_MAX_CURRENT_180_MASK 0xFF0000
+#define  SDHCI_MAX_CURRENT_180_SHIFT    16
+#define   SDHCI_MAX_CURRENT_MULTIPLIER  4
+
+/* 4C-4F reserved for more max current */
+
+#define SDHCI_SET_ACMD12_ERROR  0x50
+#define SDHCI_SET_INT_ERROR 0x52
+
+#define SDHCI_ADMA_ERROR    0x54
+
+/* 55-57 reserved */
+
+#define SDHCI_ADMA_ADDRESS  0x58
+
+/* 60-FB reserved */
+
+#define SDHCI_SLOT_INT_STATUS   0xFC
+
+#define SDHCI_HOST_VERSION  0xFE
+#define  SDHCI_VENDOR_VER_MASK  0xFF00
+#define  SDHCI_VENDOR_VER_SHIFT 8
+#define  SDHCI_SPEC_VER_MASK    0x00FF
+#define  SDHCI_SPEC_VER_SHIFT   0
+#define   SDHCI_SPEC_100    0
+#define   SDHCI_SPEC_200    1
+#define   SDHCI_SPEC_300    2
+
+/*
+ * End of controller registers.
+ */
+#define MMC_VDD_165_195     0x00000080  /* VDD voltage 1.65 - 1.95 */
+#define MMC_VDD_20_21       0x00000100  /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22       0x00000200  /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23       0x00000400  /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24       0x00000800  /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25       0x00001000  /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26       0x00002000  /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27       0x00004000  /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28       0x00008000  /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29       0x00010000  /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30       0x00020000  /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31       0x00040000  /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32       0x00080000  /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33       0x00100000  /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34       0x00200000  /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35       0x00400000  /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36       0x00800000  /* VDD voltage 3.5 ~ 3.6 */
+
+#define MMC_CAP_4_BIT_DATA  (1 << 0)    /* Can the host do 4 bit transfers */
+#define MMC_CAP_MMC_HIGHSPEED   (1 << 1)    /* Can do MMC high-speed timing */
+#define MMC_CAP_SD_HIGHSPEED    (1 << 2)    /* Can do SD high-speed timing */
+#define MMC_CAP_SDIO_IRQ    (1 << 3)    /* Can signal pending SDIO IRQs */
+#define MMC_CAP_SPI     (1 << 4)    /* Talks only SPI protocols */
+#define MMC_CAP_NEEDS_POLL  (1 << 5)    /* Needs polling for card-detection */
+#define MMC_CAP_8_BIT_DATA  (1 << 6)    /* Can the host do 8 bit transfers */
+#define MMC_CAP_DISABLE     (1 << 7)    /* Can the host be disabled */
+#define MMC_CAP_NONREMOVABLE    (1 << 8)    /* Nonremovable e.g. eMMC */
+#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9)    /* Waits while card is busy */
+#define MMC_CAP_ERASE       (1 << 10)   /* Allow erase/trim commands */
+#define MMC_CAP_1_8V_DDR    (1 << 11)   /* can support */
+                        /* DDR mode at 1.8V */
+#define MMC_CAP_1_2V_DDR    (1 << 12)   /* can support */
+                        /* DDR mode at 1.2V */
+#define MMC_CAP_POWER_OFF_CARD  (1 << 13)   /* Can power off after boot */
+#define MMC_CAP_BUS_WIDTH_TEST  (1 << 14)   /* CMD14/CMD19 bus width ok */
+#define MMC_CAP_UHS_SDR12   (1 << 15) /* Host supports UHS SDR12 mode */
+#define MMC_CAP_UHS_SDR25   (1 << 16) /* Host supports UHS SDR25 mode */
+#define MMC_CAP_UHS_SDR50   (1 << 17) /* Host supports UHS SDR50 mode */
+#define MMC_CAP_UHS_SDR104  (1 << 18) /* Host supports UHS SDR104 mode */
+#define MMC_CAP_UHS_DDR50   (1 << 19) /* Host supports UHS DDR50 mode */
+#define MMC_CAP_SET_XPC_330 (1 << 20) /* Host supports >150mA current at 3.3V */
+#define MMC_CAP_SET_XPC_300 (1 << 21) /* Host supports >150mA current at 3.0V */
+#define MMC_CAP_SET_XPC_180 (1 << 22) /* Host supports >150mA current at 1.8V */
+#define MMC_CAP_DRIVER_TYPE_A   (1 << 23) /* Host supports Driver Type A */
+#define MMC_CAP_DRIVER_TYPE_C   (1 << 24) /* Host supports Driver Type C */
+#define MMC_CAP_DRIVER_TYPE_D   (1 << 25) /* Host supports Driver Type D */
+#define MMC_CAP_MAX_CURRENT_200 (1 << 26) /* Host max current limit is 200mA */
+#define MMC_CAP_MAX_CURRENT_400 (1 << 27) /* Host max current limit is 400mA */
+#define MMC_CAP_MAX_CURRENT_600 (1 << 28) /* Host max current limit is 600mA */
+#define MMC_CAP_MAX_CURRENT_800 (1 << 29) /* Host max current limit is 800mA */
+#define MMC_CAP_CMD23       (1 << 30)   /* CMD23 supported. */
+#define MMC_CAP_HW_RESET    (1 << 31)   /* Hardware reset */
+
+
+#define MMC_CAP2_BOOTPART_NOACC (1 << 0)   /* Boot partition no access */
+#define MMC_CAP2_CACHE_CTRL (1 << 1)       /* Allow cache control */
+#define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)  /* Notify poweroff supported */
+#define MMC_CAP2_NO_MULTI_READ  (1 << 3)   /* Multiblock reads don't work */
+#define MMC_CAP2_FORCE_MULTIBLOCK (1 << 4) /* Always use multiblock transfers */
+
+#define COMPLETION_DELAY (100000)
+
+/* #define LOG_REG_ACCESS */
+
+#define TYPE_BCM2835_EMMC "bcm2835_emmc"
+#define BCM2835_EMMC(obj) \
+        OBJECT_CHECK(bcm2835_emmc_state, (obj), TYPE_BCM2835_EMMC)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    SDState *card;
+
+    uint32_t arg2;
+    uint32_t blksizecnt;
+    uint32_t arg1;
+    uint32_t cmdtm;
+    uint32_t resp0;
+    uint32_t resp1;
+    uint32_t resp2;
+    uint32_t resp3;
+    uint32_t data;
+    uint32_t status;
+    uint32_t control0;
+    uint32_t control1;
+    uint32_t interrupt;
+    uint32_t irpt_mask;
+    uint32_t irpt_en;
+    uint32_t control2;
+    uint32_t force_irpt;
+    uint32_t spi_int_spt;
+    uint32_t slotisr_ver;
+    uint32_t caps;
+    uint32_t caps2;
+    uint32_t maxcurr;
+    uint32_t maxcurr2;
+
+    int acmd;
+    int write_op;
+
+    uint32_t bytecnt;
+
+    QEMUTimer *delay_timer;
+    qemu_irq irq;
+
+} bcm2835_emmc_state;
+
+static void bcm2835_emmc_set_irq(bcm2835_emmc_state *s)
+{
+    if (s->status & SDHCI_SPACE_AVAILABLE) {
+        s->interrupt |= SDHCI_INT_SPACE_AVAIL;
+    }
+    if (s->status & SDHCI_DATA_AVAILABLE) {
+        s->interrupt |= SDHCI_INT_DATA_AVAIL;
+    }
+    if (s->irpt_en & s->irpt_mask & s->interrupt) {
+        qemu_set_irq(s->irq, 1);
+    } else {
+        qemu_set_irq(s->irq, 0);
+    }
+}
+
+static void autocmd12(bcm2835_emmc_state *s)
+{
+    SDRequest request;
+    uint8_t response[16];
+
+    if (!(s->cmdtm & SDHCI_TRNS_AUTO_CMD12)) {
+        return;
+    }
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_emmc: issuing auto-CMD12\n");
+#endif
+
+    request.cmd = 12;
+    request.arg = 0;
+    request.crc = 0;
+    sd_do_command(s->card, &request, response);
+}
+
+static void autocmd23(bcm2835_emmc_state *s)
+{
+    SDRequest request;
+    uint8_t response[16];
+
+    if (!(s->cmdtm & SDHCI_TRNS_AUTO_CMD23)) {
+        return;
+    }
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_emmc: issuing auto-CMD23\n");
+#endif
+
+    request.cmd = 23;
+    request.arg = (s->blksizecnt >> 16) & 0xffff;
+    request.crc = 0;
+    sd_do_command(s->card, &request, response);
+}
+
+static void delayed_completion(void *opaque)
+{
+    bcm2835_emmc_state *s = (bcm2835_emmc_state *)opaque;
+
+    s->interrupt |= SDHCI_INT_DATA_END;
+    autocmd12(s);
+
+    bcm2835_emmc_set_irq(s);
+}
+
+
+static uint64_t bcm2835_emmc_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_emmc_state *s = (bcm2835_emmc_state *)opaque;
+    uint32_t res = 0;
+    uint8_t tmp = 0;
+    int set_irq = 0;
+    uint32_t blkcnt;
+    uint8_t cmd;
+    int64_t now;
+
+    assert(size == 4);
+
+    switch (offset) {
+    case SDHCI_ARGUMENT2:      /* ARG2 */
+        res = s->arg2;
+        break;
+    case SDHCI_BLOCK_SIZE:     /* BLKSIZECNT */
+        res = s->blksizecnt;
+        break;
+    case SDHCI_ARGUMENT:       /* ARG1 */
+        res = s->arg1;
+        break;
+    case SDHCI_TRANSFER_MODE:   /* CMDTM */
+        res = s->cmdtm;
+        break;
+    case SDHCI_RESPONSE+0:      /* RESP0 */
+        res = s->resp0;
+        break;
+    case SDHCI_RESPONSE+4:      /* RESP1 */
+        res = s->resp1;
+        break;
+    case SDHCI_RESPONSE+8:      /* RESP2 */
+        res = s->resp2;
+        break;
+    case SDHCI_RESPONSE+12:      /* RESP3 */
+        res = s->resp3;
+        break;
+    case SDHCI_BUFFER:          /* DATA */
+        cmd = ((s->cmdtm >> (16 + 8)) & 0x3f);
+
+        s->data = "">
+        tmp = sd_read_data(s->card);
+        s->data |= (tmp << 0);
+        tmp = sd_read_data(s->card);
+        s->data |= (tmp << 8);
+        tmp = sd_read_data(s->card);
+        s->data |= (tmp << 16);
+        tmp = sd_read_data(s->card);
+        s->data |= (tmp << 24);
+
+        s->status |= SDHCI_DATA_AVAILABLE;
+
+        s->bytecnt += 4;
+
+        if (s->bytecnt == 512) {
+            s->bytecnt = 0;
+            if (s->cmdtm & SDHCI_TRNS_BLK_CNT_EN) {
+                blkcnt = (s->blksizecnt >> 16) & 0xffff;
+                blkcnt--;
+                s->blksizecnt = (blkcnt << 16) | (s->blksizecnt & 0xffff);
+                if (blkcnt == 0) {
+                    s->status &= ~SDHCI_DATA_AVAILABLE;
+
+                    if (COMPLETION_DELAY > 0) {
+                        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / SCALE_US;
+                        timer_mod(s->delay_timer,
+                            now + COMPLETION_DELAY);
+                    } else {
+                        s->interrupt |= SDHCI_INT_DATA_END;
+                        autocmd12(s);
+                    }
+
+                    /* s->interrupt |= SDHCI_INT_DATA_END; */
+                    /* autocmd12(s); */
+                }
+            }
+            if (!s->acmd && (cmd == 17)) {
+                /* Single read */
+                s->status &= ~SDHCI_DATA_AVAILABLE;
+
+                s->interrupt |= SDHCI_INT_DATA_END;
+            }
+        }
+        if (!sd_data_ready(s->card)) {
+            s->status &= ~SDHCI_DATA_AVAILABLE;
+
+            s->interrupt |= SDHCI_INT_DATA_END;
+        }
+        set_irq = 1;
+        res = s->data;
+        break;
+    case SDHCI_PRESENT_STATE:   /* STATUS */
+        res = s->status;
+        break;
+    case SDHCI_HOST_CONTROL:    /* CONTROL0 */
+        res = s->control0;
+        break;
+    case SDHCI_CLOCK_CONTROL:   /* CONTROL1 */
+        res = s->control1;
+        break;
+    case SDHCI_INT_STATUS:      /* INTERRUPT */
+        res = s->interrupt;
+        break;
+    case SDHCI_INT_ENABLE:      /* IRPT_MASK */
+        res = s->irpt_mask;
+        break;
+    case SDHCI_SIGNAL_ENABLE:   /* IRPT_EN */
+        res = s->irpt_en;
+        break;
+    case SDHCI_CAPABILITIES:
+        res = s->caps;
+        break;
+    case SDHCI_CAPABILITIES_1:
+        res = s->caps;
+        break;
+    case SDHCI_ACMD12_ERR:      /* CONTROL2 */
+        res = s->control2;
+        break;
+    case SDHCI_SET_ACMD12_ERROR:    /* FORCE_IRPT */
+        res = s->force_irpt;
+        break;
+    case SDHCI_SLOT_INT_STATUS: /* SLOTISR_VERSION */
+        res = s->slotisr_ver;
+        break;
+    case SDHCI_MAX_CURRENT:
+        res = s->maxcurr;
+        break;
+    case SDHCI_MAX_CURRENT+4:
+        res = s->maxcurr2;
+        break;
+    default:
+        break;
+    }
+
+#ifdef LOG_REG_ACCESS
+    if (offset != SDHCI_BUFFER) {
+        printf("[QEMU] bcm2835_emmc: read(%x) %08x\n", (int)offset, res);
+    }
+#endif
+
+    if (set_irq) {
+        bcm2835_emmc_set_irq(s);
+    }
+
+    return res;
+}
+
+static void bcm2835_emmc_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    bcm2835_emmc_state *s = (bcm2835_emmc_state *)opaque;
+    uint8_t cmd;
+    SDRequest request;
+    uint8_t response[16];
+    int resplen;
+    uint32_t blkcnt;
+    int64_t now;
+
+    assert(size == 4);
+
+#ifdef LOG_REG_ACCESS
+    if (offset != SDHCI_BUFFER) {
+        printf("[QEMU] bcm2835_emmc: write(%x) %08x\n", (int)offset,
+            (uint32_t)value);
+    }
+#endif
+
+    switch (offset) {
+    case SDHCI_ARGUMENT2:      /* ARG2 */
+        s->arg2 = value;
+        break;
+    case SDHCI_BLOCK_SIZE:     /* BLKSIZECNT */
+        s->blksizecnt = value;
+        break;
+    case SDHCI_ARGUMENT:       /* ARG1 */
+        s->arg1 = value;
+        break;
+    case SDHCI_TRANSFER_MODE:   /* CMDTM */
+        s->cmdtm = value;
+        cmd = ((value >> (16 + 8)) & 0x3f);
+
+#ifdef LOG_REG_ACCESS
+        printf("[QEMU] bcm2835_emmc: starting %sCMD%d %08x ",
+            (s->acmd ? "A" : ""), cmd, s->arg1);
+        if (s->cmdtm & SDHCI_TRNS_BLK_CNT_EN) {
+            printf("BlkCnt ");
+        }
+        if (s->cmdtm & SDHCI_TRNS_AUTO_CMD12) {
+            printf("Auto-CMD12 ");
+        }
+        if (s->cmdtm & SDHCI_TRNS_AUTO_CMD23) {
+            printf("Auto-CMD23 ");
+        }
+        printf("\n");
+#endif
+
+        if (!s->acmd && (cmd == 18 || cmd == 25)) {
+            autocmd23(s);
+        }
+
+        request.cmd = cmd;
+        request.arg = s->arg1;
+        request.crc = 0;
+
+        s->bytecnt = 0;
+
+        s->status &= ~SDHCI_DATA_AVAILABLE;
+        s->status &= ~SDHCI_SPACE_AVAILABLE;
+
+        resplen = sd_do_command(s->card, &request, response);
+
+        if (resplen > 0) {
+            if (resplen == 4) {
+                s->resp0 = (response[0] << 24)
+                    | (response[1] << 16)
+                    | (response[2] << 8)
+                    | (response[3] << 0);
+                if (!s->acmd && ((cmd == 24) || (cmd == 25))) {
+                    s->status |= SDHCI_SPACE_AVAILABLE;
+                }
+            } else if (resplen == 16) {
+                s->resp3 = 0
+                    | (response[1-1] << 16)
+                    | (response[2-1] << 8)
+                    | (response[3-1] << 0);
+                s->resp2 = 0
+                    | (response[0+4-1] << 24)
+                    | (response[1+4-1] << 16)
+                    | (response[2+4-1] << 8)
+                    | (response[3+4-1] << 0);
+                s->resp1 = 0
+                    | (response[0+8-1] << 24)
+                    | (response[1+8-1] << 16)
+                    | (response[2+8-1] << 8)
+                    | (response[3+8-1] << 0);
+                s->resp0 = 0
+                    | (response[0+12-1] << 24)
+                    | (response[1+12-1] << 16)
+                    | (response[2+12-1] << 8)
+                    | (response[3+12-1] << 0);
+            }
+
+            s->interrupt |= SDHCI_INT_RESPONSE;
+
+            if (!s->acmd && (cmd == 12)) {
+                /* Stop transmission */
+                s->status &= ~SDHCI_SPACE_AVAILABLE;
+                s->interrupt |= SDHCI_INT_DATA_END;
+            } else {
+                if (sd_data_ready(s->card)) {
+#ifdef LOG_REG_ACCESS
+                    printf("[QEMU] bcm2835_emmc: data available\n");
+#endif
+                    s->status |= SDHCI_DATA_AVAILABLE;
+                }
+            }
+            bcm2835_emmc_set_irq(s);
+        } else {
+            /* Unrecognized commands */
+            if ((!s->acmd && (cmd == 52))
+                || (!s->acmd && (cmd == 5))
+       ) {
+                s->interrupt |= SDHCI_INT_TIMEOUT;
+                s->interrupt |= SDHCI_INT_ERROR;
+            }
+            if (!s->acmd && (cmd == 0)) {
+                s->interrupt |= SDHCI_INT_RESPONSE;
+            }
+            if (!s->acmd && (cmd == 7)) {
+                s->interrupt |= SDHCI_INT_RESPONSE;
+            }
+            bcm2835_emmc_set_irq(s);
+        }
+        if (cmd == 55) {
+            s->acmd = 1;
+        } else {
+            s->acmd = 0;
+        }
+        break;
+    case SDHCI_BUFFER:          /* DATA */
+        cmd = ((s->cmdtm >> (16 + 8)) & 0x3f);
+
+        s->data = "">
+
+        sd_write_data(s->card, (value >> 0) & 0xff);
+        sd_write_data(s->card, (value >> 8) & 0xff);
+        sd_write_data(s->card, (value >> 16) & 0xff);
+        sd_write_data(s->card, (value >> 24) & 0xff);
+
+        s->status |= SDHCI_SPACE_AVAILABLE;
+
+        s->bytecnt += 4;
+
+        if (s->bytecnt == 512) {
+            s->bytecnt = 0;
+            if (s->cmdtm & SDHCI_TRNS_BLK_CNT_EN) {
+                blkcnt = (s->blksizecnt >> 16) & 0xffff;
+                blkcnt--;
+                s->blksizecnt = (blkcnt << 16) | (s->blksizecnt & 0xffff);
+                if (blkcnt == 0) {
+                    /* s->interrupt &= ~SDHCI_INT_SPACE_AVAIL; */
+                    /* s->status &= ~SDHCI_SPACE_AVAILABLE; */
+
+                    if (COMPLETION_DELAY > 0) {
+                        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / SCALE_US;
+                        timer_mod(s->delay_timer,
+                            now + COMPLETION_DELAY);
+                    } else {
+                        s->interrupt |= SDHCI_INT_DATA_END;
+                        autocmd12(s);
+                    }
+
+                    /* s->interrupt |= SDHCI_INT_DATA_END; */
+                    /* autocmd12(s); */
+                }
+            }
+            if (!s->acmd && (cmd == 24)) {
+                /* Single write */
+                s->status &= ~SDHCI_SPACE_AVAILABLE;
+
+                s->interrupt |= SDHCI_INT_DATA_END;
+            }
+        }
+        bcm2835_emmc_set_irq(s);
+        break;
+    case SDHCI_HOST_CONTROL:    /* CONTROL0 */
+        s->control0 &= ~0x007f0026;
+        value &= 0x007f0026;
+        s->control0 |= value;
+        break;
+    case SDHCI_CLOCK_CONTROL:  /* CONTROL1 */
+        s->control0 &= ~0x070fffe7;
+        value &= 0x070fffe7;
+        if (value & ((SDHCI_RESET_ALL
+            | SDHCI_RESET_CMD
+            | SDHCI_RESET_DATA) << 24)) {
+            /* Reset */
+            value &= ~((SDHCI_RESET_ALL
+                | SDHCI_RESET_CMD
+                | SDHCI_RESET_DATA) << 24);
+        }
+        s->control1 |= value;
+        break;
+    case SDHCI_INT_STATUS:      /* INTERRUPT */
+        s->interrupt &= ~value;
+        bcm2835_emmc_set_irq(s);
+        break;
+
+    case SDHCI_INT_ENABLE:      /* IRPT_MASK */
+        s->irpt_mask = value;
+        break;
+    case SDHCI_SIGNAL_ENABLE:   /* IRPT_EN */
+        s->irpt_en = value;
+        break;
+    case SDHCI_ACMD12_ERR:      /* CONTROL2 */
+        s->control2 &= ~0x00e7009f;
+        value &= 0x00e7009f;
+        s->control2 |= value;
+        break;
+    case SDHCI_SET_ACMD12_ERROR:    /* FORCE_IRPT */
+        s->force_irpt = value;
+        break;
+
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps bcm2835_emmc_ops = {
+    .read = bcm2835_emmc_read,
+    .write = bcm2835_emmc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_bcm2835_emmc = {
+    .name = "bcm2835_emmc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_emmc_init(SysBusDevice *sbd)
+{
+    /* bcm2835_emmc_state *s = FROM_SYSBUS(bcm2835_emmc_state, dev); */
+    DriveInfo *di;
+
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_emmc_state *s = BCM2835_EMMC(dev);
+
+    di = drive_get(IF_SD, 0, 0);
+    if (!di) {
+        fprintf(stderr, "bcm2835_emmc: missing SD card\n");
+        exit(1);
+    }
+    s->card = sd_init(di->bdrv, 0);
+
+    s->arg2 = 0;
+    s->blksizecnt = 0;
+    s->arg1 = 0;
+    s->cmdtm = 0;
+    s->resp0 = 0;
+    s->resp1 = 0;
+    s->resp2 = 0;
+    s->resp3 = 0;
+    s->data = "">
+    s->status = (0x1ff << 16);
+    s->control0 = 0;
+    s->control1 = SDHCI_CLOCK_INT_STABLE;
+    s->interrupt = 0;
+    s->irpt_mask = 0;
+    s->irpt_en = 0;
+    s->control2 = 0;
+    s->force_irpt = 0;
+    s->spi_int_spt = 0;
+    s->slotisr_ver = (0x9900 | SDHCI_SPEC_300) << 16;
+    s->caps = 0;
+    s->caps2 = 0;
+    s->maxcurr = 1;
+    s->maxcurr2 = 0;
+
+    s->acmd = 0;
+    s->write_op = 0;
+
+    s->delay_timer = timer_new(QEMU_CLOCK_VIRTUAL,
+        SCALE_US, delayed_completion, s);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_emmc_ops, s,
+        "bcm2835_emmc", 0x100000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_emmc, s);
+
+    sysbus_init_irq(sbd, &s->irq);
+
+    return 0;
+}
+
+static void bcm2835_emmc_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = bcm2835_emmc_init;
+}
+
+static TypeInfo bcm2835_emmc_info = {
+    .name          = "bcm2835_emmc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_emmc_state),
+    .class_init    = bcm2835_emmc_class_init,
+};
+
+static void bcm2835_emmc_register_types(void)
+{
+    type_register_static(&bcm2835_emmc_info);
+}
+
+type_init(bcm2835_emmc_register_types)
diff --git a/hw/arm/bcm2835_fb.c b/hw/arm/bcm2835_fb.c
new file mode 100644
index 0000000..36b5e6e
--- /dev/null
+++ b/hw/arm/bcm2835_fb.c
@@ -0,0 +1,379 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+/* Heavily based on milkymist-vgafb.c, copyright terms below. */
+
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010-2012 Michael Walle <address@hidden>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+#include "ui/console.h"
+#include "hw/display/framebuffer.h"
+#include "ui/pixel_ops.h"
+
+#include "exec/cpu-common.h"
+
+#include "bcm2835_common.h"
+
+/* #define LOG_REG_ACCESS */
+
+#define FRAMESKIP 1
+
+bcm2835_fb_type bcm2835_fb;
+
+#define TYPE_BCM2835_FB "bcm2835_fb"
+#define BCM2835_FB(obj) OBJECT_CHECK(bcm2835_fb_state, (obj), TYPE_BCM2835_FB)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    int pending;
+    qemu_irq mbox_irq;
+} bcm2835_fb_state;
+
+static void fb_invalidate_display(void *opaque)
+{
+    /* bcm2835_fb_state *s = (bcm2835_fb_state *)opaque; */
+    bcm2835_fb.invalidate = 1;
+}
+
+static void draw_line_src16(void *opaque, uint8_t *d, const uint8_t *s,
+        int width, int deststep)
+{
+    uint16_t rgb565;
+    uint32_t rgb888;
+    uint8_t r, g, b;
+    DisplaySurface *surface = qemu_console_surface(bcm2835_fb.con);
+
+    int bpp = surface_bits_per_pixel(surface);
+
+    while (width--) {
+        switch (bcm2835_fb.bpp) {
+        case 8:
+            rgb888 = ldl_phys(bcm2835_vcram_base + (*s << 2));
+            r = (rgb888 >> 0) & 0xff;
+            g = (rgb888 >> 8) & 0xff;
+            b = (rgb888 >> 16) & 0xff;
+            s++;
+            break;
+        case 16:
+            rgb565 = lduw_raw(s);
+            r = ((rgb565 >> 11) & 0x1f) << 3;
+            g = ((rgb565 >>  5) & 0x3f) << 2;
+            b = ((rgb565 >>  0) & 0x1f) << 3;
+            s += 2;
+            break;
+        case 24:
+            rgb888 = ldl_raw(s);
+            r = (rgb888 >> 0) & 0xff;
+            g = (rgb888 >> 8) & 0xff;
+            b = (rgb888 >> 16) & 0xff;
+            s += 3;
+            break;
+        case 32:
+            rgb888 = ldl_raw(s);
+            r = (rgb888 >> 0) & 0xff;
+            g = (rgb888 >> 8) & 0xff;
+            b = (rgb888 >> 16) & 0xff;
+            s += 4;
+            break;
+        default:
+            r = 0;
+            g = 0;
+            b = 0;
+            break;
+        }
+
+        switch (bpp) {
+        case 8:
+            *d++ = rgb_to_pixel8(r, g, b);
+            break;
+        case 15:
+            *(uint16_t *)d = rgb_to_pixel15(r, g, b);
+            d += 2;
+            break;
+        case 16:
+            *(uint16_t *)d = rgb_to_pixel16(r, g, b);
+            d += 2;
+            break;
+        case 24:
+            rgb888 = rgb_to_pixel24(r, g, b);
+            *d++ = rgb888 & 0xff;
+            *d++ = (rgb888 >> 8) & 0xff;
+            *d++ = (rgb888 >> 16) & 0xff;
+            break;
+        case 32:
+            *(uint32_t *)d = rgb_to_pixel32(r, g, b);
+            d += 4;
+            break;
+        default:
+            return;
+        }
+    }
+}
+
+static void fb_update_display(void *opaque)
+{
+    bcm2835_fb_state *s = (bcm2835_fb_state *)opaque;
+    int first = 0;
+    int last = 0;
+    drawfn fn;
+    DisplaySurface *surface = qemu_console_surface(bcm2835_fb.con);
+
+    int src_width = 0;
+    int dest_width = 0;
+
+    static uint32_t frame; /* 0 */
+
+    if (++frame < FRAMESKIP) {
+        return;
+    } else {
+        frame = 0;
+    }
+
+    if (bcm2835_fb.lock) {
+        return;
+    }
+
+    if (!bcm2835_fb.xres) {
+        return;
+    }
+
+    src_width = bcm2835_fb.xres * (bcm2835_fb.bpp >> 3);
+
+    dest_width = bcm2835_fb.xres;
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        return;
+    case 8:
+        break;
+    case 15:
+        dest_width *= 2;
+        break;
+    case 16:
+        dest_width *= 2;
+        break;
+    case 24:
+        dest_width *= 3;
+        break;
+    case 32:
+        dest_width *= 4;
+        break;
+    default:
+        hw_error("milkymist_vgafb: bad color depth\n");
+        break;
+    }
+
+
+
+    fn = draw_line_src16;
+
+    framebuffer_update_display(surface,
+        sysbus_address_space(&s->busdev),
+        bcm2835_fb.base,
+        bcm2835_fb.xres,
+        bcm2835_fb.yres,
+        src_width,
+        dest_width,
+        0,
+        bcm2835_fb.invalidate,
+        fn,
+        NULL,
+        &first, &last);
+    if (first >= 0) {
+        dpy_gfx_update(bcm2835_fb.con, 0, first,
+            bcm2835_fb.xres, last - first + 1);
+    }
+
+    bcm2835_fb.invalidate = 0;
+}
+
+
+
+static void bcm2835_fb_mbox_push(bcm2835_fb_state *s, uint32_t value)
+{
+    value &= ~0xf;
+    bcm2835_fb.lock = 1;
+
+    bcm2835_fb.xres = ldl_phys(value);
+    bcm2835_fb.yres = ldl_phys(value + 4);
+    bcm2835_fb.xres_virtual = ldl_phys(value + 8);
+    bcm2835_fb.yres_virtual = ldl_phys(value + 12);
+
+    bcm2835_fb.bpp = ldl_phys(value + 20);
+    bcm2835_fb.xoffset = ldl_phys(value + 24);
+    bcm2835_fb.yoffset = ldl_phys(value + 28);
+
+    bcm2835_fb.base = bcm2835_vcram_base | (value & 0xc0000000);
+    bcm2835_fb.base += BCM2835_FB_OFFSET;
+
+    /* TODO - Manage properly virtual resolution */
+
+    bcm2835_fb.pitch = bcm2835_fb.xres * (bcm2835_fb.bpp >> 3);
+    bcm2835_fb.size = bcm2835_fb.yres * bcm2835_fb.pitch;
+
+    stl_phys(value + 16, bcm2835_fb.pitch);
+    stl_phys(value + 32, bcm2835_fb.base);
+    stl_phys(value + 36, bcm2835_fb.size);
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_fb: mbox_push res=(%d %d)\n",
+        bcm2835_fb.xres, bcm2835_fb.yres);
+#endif
+
+    bcm2835_fb.invalidate = 1;
+    qemu_console_resize(bcm2835_fb.con, bcm2835_fb.xres, bcm2835_fb.yres);
+    bcm2835_fb.lock = 0;
+}
+
+static uint64_t bcm2835_fb_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_fb_state *s = (bcm2835_fb_state *)opaque;
+    uint32_t res = 0;
+
+    switch (offset) {
+    case 0:
+        res = MBOX_CHAN_FB;
+        s->pending = 0;
+        qemu_set_irq(s->mbox_irq, 0);
+        break;
+    case 4:
+        res = s->pending;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_fb_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+    return res;
+}
+static void bcm2835_fb_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+    bcm2835_fb_state *s = (bcm2835_fb_state *)opaque;
+    switch (offset) {
+    case 0:
+        if (!s->pending) {
+            s->pending = 1;
+            bcm2835_fb_mbox_push(s, value);
+            qemu_set_irq(s->mbox_irq, 1);
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_fb_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+}
+
+
+static const MemoryRegionOps bcm2835_fb_ops = {
+    .read = bcm2835_fb_read,
+    .write = bcm2835_fb_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_bcm2835_fb = {
+    .name = "bcm2835_fb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+static const GraphicHwOps vgafb_ops = {
+    .invalidate  = fb_invalidate_display,
+    .gfx_update  = fb_update_display,
+};
+
+static int bcm2835_fb_init(SysBusDevice *sbd)
+{
+    /* bcm2835_fb_state *s = FROM_SYSBUS(bcm2835_fb_state, dev); */
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_fb_state *s = BCM2835_FB(dev);
+
+    s->pending = 0;
+
+    /* bcm2835_fb.invalidate = 0; */
+    bcm2835_fb.xres = 640;
+    bcm2835_fb.yres = 480;
+    bcm2835_fb.xres_virtual = 640;
+    bcm2835_fb.yres_virtual = 480;
+    /* bcm2835_fb.xres = 1024; */
+    /* bcm2835_fb.yres = 768; */
+    /* bcm2835_fb.xres_virtual = 1024; */
+    /* bcm2835_fb.yres_virtual = 768; */
+
+    bcm2835_fb.bpp = 16;
+    bcm2835_fb.xoffset = 0;
+    bcm2835_fb.yoffset = 0;
+
+    bcm2835_fb.base = bcm2835_vcram_base;
+    bcm2835_fb.base += BCM2835_FB_OFFSET;
+
+    bcm2835_fb.pitch = bcm2835_fb.xres * (bcm2835_fb.bpp >> 3);
+    bcm2835_fb.size = bcm2835_fb.yres * bcm2835_fb.pitch;
+
+    bcm2835_fb.invalidate = 1;
+    bcm2835_fb.lock = 1;
+
+    sysbus_init_irq(sbd, &s->mbox_irq);
+
+    bcm2835_fb.con = graphic_console_init(dev, &vgafb_ops, s);
+    bcm2835_fb.lock = 0;
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_fb_ops, s,
+        "bcm2835_fb", 0x10);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_fb, s);
+
+    return 0;
+}
+
+static void bcm2835_fb_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = bcm2835_fb_init;
+}
+
+static TypeInfo bcm2835_fb_info = {
+    .name          = "bcm2835_fb",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_fb_state),
+    .class_init    = bcm2835_fb_class_init,
+};
+
+static void bcm2835_fb_register_types(void)
+{
+    type_register_static(&bcm2835_fb_info);
+}
+
+type_init(bcm2835_fb_register_types)
diff --git a/hw/arm/bcm2835_ic.c b/hw/arm/bcm2835_ic.c
new file mode 100644
index 0000000..b535b3f
--- /dev/null
+++ b/hw/arm/bcm2835_ic.c
@@ -0,0 +1,255 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+/* Heavily based on pl190.c, copyright terms below. */
+
+/*
+ * Arm PrimeCell PL190 Vector Interrupt Controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+
+#define IR_B 2
+#define IR_1 0
+#define IR_2 1
+
+#define TYPE_BCM2835_IC "bcm2835_ic"
+#define BCM2835_IC(obj) OBJECT_CHECK(bcm2835_ic_state, (obj), TYPE_BCM2835_IC)
+
+
+typedef struct bcm2835_ic_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    uint32_t level[3];
+    uint32_t irq_enable[3];
+    int fiq_enable;
+    int fiq_select;
+    qemu_irq irq;
+    qemu_irq fiq;
+} bcm2835_ic_state;
+
+/* Update interrupts.  */
+static void bcm2835_ic_update(bcm2835_ic_state *s)
+{
+    int set;
+    int i;
+
+    set = 0;
+    if (s->fiq_enable) {
+        set = s->level[s->fiq_select >> 5] & (1u << (s->fiq_select & 0x1f));
+    }
+    qemu_set_irq(s->fiq, set);
+
+    set = 0;
+    for (i = 0; i < 3; i++) {
+        set |= (s->level[i] & s->irq_enable[i]);
+    }
+    qemu_set_irq(s->irq, set);
+
+}
+
+static void bcm2835_ic_set_irq(void *opaque, int irq, int level)
+{
+    bcm2835_ic_state *s = (bcm2835_ic_state *)opaque;
+
+    if (irq >= 0 && irq <= 71) {
+        if (level) {
+                s->level[irq >> 5] |= 1u << (irq & 0x1f);
+        } else {
+                s->level[irq >> 5] &= ~(1u << (irq & 0x1f));
+        }
+    } else {
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_ic_set_irq: Bad irq %d\n", irq);
+    }
+
+    bcm2835_ic_update(s);
+}
+
+static int irq_dups[] = { 7, 9, 10, 18, 19, 53, 54, 55, 56, 57, 62, -1 };
+
+static uint64_t bcm2835_ic_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_ic_state *s = (bcm2835_ic_state *)opaque;
+    int i;
+    int p = 0;
+    uint32_t res = 0;
+
+    switch (offset) {
+    case 0x00:  /* IRQ basic pending */
+        /* bits 0-7 - ARM irqs */
+        res = (s->level[IR_B] & s->irq_enable[IR_B]) & 0xff;
+        for (i = 0; i < 64; i++) {
+            if (i == irq_dups[p]) {
+                /* bits 10-20 - selected GPU irqs */
+                if (s->level[i >> 5] & s->irq_enable[i >> 5]
+                    & (1u << (i & 0x1f))) {
+                    res |= (1u << (10 + p));
+                }
+                p++;
+            } else {
+                /* bits 8-9 - one or more bits set in pending registers 1-2 */
+                if (s->level[i >> 5] & s->irq_enable[i >> 5]
+                    & (1u << (i & 0x1f))) {
+                    res |= (1u << (8 + (i >> 5)));
+                }
+            }
+        }
+        break;
+    case 0x04:  /* IRQ pending 1 */
+        res = s->level[IR_1] & s->irq_enable[IR_1];
+        break;
+    case 0x08:  /* IRQ pending 2 */
+        res = s->level[IR_2] & s->irq_enable[IR_2];
+        break;
+    case 0x0C:  /* FIQ register */
+        res = (s->fiq_enable << 7) | s->fiq_select;
+        break;
+    case 0x10:  /* Interrupt enable register 1 */
+        res = s->irq_enable[IR_1];
+        break;
+    case 0x14:  /* Interrupt enable register 2 */
+        res = s->irq_enable[IR_2];
+        break;
+    case 0x18:  /* Base interrupt enable register */
+        res = s->irq_enable[IR_B];
+        break;
+    case 0x1C:  /* Interrupt disable register 1 */
+        res = ~s->irq_enable[IR_1];
+        break;
+    case 0x20:  /* Interrupt disable register 2 */
+        res = ~s->irq_enable[IR_2];
+        break;
+    case 0x24:  /* Base interrupt disable register */
+        res = ~s->irq_enable[IR_B];
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_ic_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+
+    return res;
+}
+
+static void bcm2835_ic_write(void *opaque, hwaddr offset,
+    uint64_t val, unsigned size)
+{
+    bcm2835_ic_state *s = (bcm2835_ic_state *)opaque;
+
+    switch (offset) {
+    case 0x0C:  /* FIQ register */
+        s->fiq_select = (val & 0x7f);
+        s->fiq_enable = (val >> 7) & 0x1;
+        break;
+    case 0x10:  /* Interrupt enable register 1 */
+        s->irq_enable[IR_1] |= val;
+        break;
+    case 0x14:  /* Interrupt enable register 2 */
+        s->irq_enable[IR_2] |= val;
+        break;
+    case 0x18:  /* Base interrupt enable register */
+        s->irq_enable[IR_B] |= (val & 0xff);
+        break;
+    case 0x1C:  /* Interrupt disable register 1 */
+        s->irq_enable[IR_1] &= ~val;
+        break;
+    case 0x20:  /* Interrupt disable register 2 */
+        s->irq_enable[IR_2] &= ~val;
+        break;
+    case 0x24:  /* Base interrupt disable register */
+        s->irq_enable[IR_B] &= (~val & 0xff);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_ic_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+    bcm2835_ic_update(s);
+}
+
+static const MemoryRegionOps bcm2835_ic_ops = {
+    .read = bcm2835_ic_read,
+    .write = bcm2835_ic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void bcm2835_ic_reset(DeviceState *d)
+{
+    /* bcm2835_ic_state *s = DO_UPCAST(bcm2835_ic_state, busdev.qdev, d); */
+    bcm2835_ic_state *s = BCM2835_IC(d);
+    int i;
+
+    for (i = 0; i < 3; i++) {
+        s->irq_enable[i] = 0;
+    }
+    s->fiq_enable = 0;
+    s->fiq_select = 0;
+}
+
+static int bcm2835_ic_init(SysBusDevice *sbd)
+{
+    /* bcm2835_ic_state *s = FROM_SYSBUS(bcm2835_ic_state, dev); */
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_ic_state *s = BCM2835_IC(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_ic_ops, s,
+        "bcm2835_ic", 0x200);
+    /* sysbus_init_mmio(dev, &s->iomem); */
+    sysbus_init_mmio(sbd, &s->iomem);
+
+    /* qdev_init_gpio_in(&dev->qdev, bcm2835_ic_set_irq, 72); */
+    qdev_init_gpio_in(dev, bcm2835_ic_set_irq, 72);
+    /* sysbus_init_irq(dev, &s->irq); */
+    /* sysbus_init_irq(dev, &s->fiq); */
+    sysbus_init_irq(sbd, &s->irq);
+    sysbus_init_irq(sbd, &s->fiq);
+    return 0;
+}
+
+static const VMStateDescription vmstate_bcm2835_ic = {
+    .name = "bcm2835_ic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(level, bcm2835_ic_state, 3),
+        VMSTATE_UINT32_ARRAY(irq_enable, bcm2835_ic_state, 3),
+        VMSTATE_INT32(fiq_enable, bcm2835_ic_state),
+        VMSTATE_INT32(fiq_select, bcm2835_ic_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = bcm2835_ic_init;
+    dc->no_user = 1;
+    dc->reset = bcm2835_ic_reset;
+    dc->vmsd = &vmstate_bcm2835_ic;
+}
+
+static TypeInfo bcm2835_ic_info = {
+    .name          = "bcm2835_ic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_ic_state),
+    .class_init    = bcm2835_ic_class_init,
+};
+
+static void bcm2835_ic_register_types(void)
+{
+    type_register_static(&bcm2835_ic_info);
+}
+
+type_init(bcm2835_ic_register_types)
diff --git a/hw/arm/bcm2835_mphi.c b/hw/arm/bcm2835_mphi.c
new file mode 100644
index 0000000..c6dfc20
--- /dev/null
+++ b/hw/arm/bcm2835_mphi.c
@@ -0,0 +1,190 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+
+/* #define LOG_REG_ACCESS */
+
+#define TYPE_BCM2835_MPHI "bcm2835_mphi"
+#define BCM2835_MPHI(obj) \
+        OBJECT_CHECK(bcm2835_mphi_state, (obj), TYPE_BCM2835_MPHI)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    uint32_t mphi_base;
+    uint32_t mphi_ctrl;
+    uint32_t mphi_outdda;
+    uint32_t mphi_outddb;
+    uint32_t mphi_intstat;
+
+    qemu_irq irq;
+
+} bcm2835_mphi_state;
+
+
+static void bcm2835_mphi_update_irq(bcm2835_mphi_state *s)
+{
+    if (s->mphi_intstat) {
+        qemu_set_irq(s->irq, 1);
+    } else {
+        qemu_set_irq(s->irq, 0);
+    }
+}
+
+static uint64_t bcm2835_mphi_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_mphi_state *s = (bcm2835_mphi_state *)opaque;
+    uint32_t res = 0;
+
+    assert(size == 4);
+
+    switch (offset) {
+    case 0x00:    /* mphi_base */
+        res = s->mphi_base;
+        break;
+    case 0x28:    /* mphi_outdda */
+        res = s->mphi_outdda;
+        break;
+    case 0x2c:    /* mphi_outddb */
+        res = s->mphi_outddb;
+        break;
+    case 0x4c:    /* mphi_ctrl */
+        res = s->mphi_ctrl;
+        break;
+    case 0x50:    /* mphi_intstat */
+        res = s->mphi_intstat;
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_mphi_read: Bad offset %x\n", (int)offset);
+        res = 0;
+        break;
+    }
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_mphi: read(%x) %08x\n", (int)offset, res);
+#endif
+
+    return res;
+}
+
+static void bcm2835_mphi_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+    bcm2835_mphi_state *s = (bcm2835_mphi_state *)opaque;
+    int set_irq = 0;
+
+    assert(size == 4);
+
+    switch (offset) {
+    case 0x00:    /* mphi_base */
+        s->mphi_base = value;
+        break;
+    case 0x28:    /* mphi_outdda */
+        s->mphi_outdda = value;
+        break;
+    case 0x2c:    /* mphi_outddb */
+        s->mphi_outddb = value;
+        if (value & (1 << 29)) {
+            /* Enable MPHI interrupt */
+            s->mphi_intstat |= (1 << 16);
+            set_irq = 1;
+        }
+        break;
+    case 0x4c:    /* mphi_ctrl */
+        s->mphi_ctrl &= ~(1 << 31);
+        s->mphi_ctrl |= value & (1 << 31);
+
+        s->mphi_ctrl &= ~(3 << 16);
+        if (value & (1 << 16)) {
+            s->mphi_ctrl |= (3 << 16);
+        }
+
+        break;
+    case 0x50:    /* mphi_intstat */
+        s->mphi_intstat &= ~value;
+        set_irq = 1;
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_mphi_write: Bad offset %x\n", (int)offset);
+        break;
+    }
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_mphi: write(%x) %08x\n", (int)offset,
+        (uint32_t)value);
+#endif
+
+    if (set_irq) {
+        bcm2835_mphi_update_irq(s);
+    }
+}
+
+static const MemoryRegionOps bcm2835_mphi_ops = {
+    .read = bcm2835_mphi_read,
+    .write = bcm2835_mphi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_bcm2835_mphi = {
+    .name = "bcm2835_mphi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_mphi_init(SysBusDevice *sbd)
+{
+    /* bcm2835_mphi_state *s = FROM_SYSBUS(bcm2835_mphi_state, dev); */
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_mphi_state *s = BCM2835_MPHI(dev);
+
+    s->mphi_base = 0;
+    s->mphi_ctrl = 0;
+    s->mphi_outdda = 0;
+    s->mphi_outddb = 0;
+    s->mphi_intstat = 0;
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_mphi_ops, s,
+        "bcm2835_mphi", 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_mphi, s);
+
+    sysbus_init_irq(sbd, &s->irq);
+
+    return 0;
+}
+
+static void bcm2835_mphi_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = bcm2835_mphi_init;
+}
+
+static TypeInfo bcm2835_mphi_info = {
+    .name          = "bcm2835_mphi",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_mphi_state),
+    .class_init    = bcm2835_mphi_class_init,
+};
+
+static void bcm2835_mphi_register_types(void)
+{
+    type_register_static(&bcm2835_mphi_info);
+}
+
+type_init(bcm2835_mphi_register_types)
diff --git a/hw/arm/bcm2835_platform.h b/hw/arm/bcm2835_platform.h
new file mode 100644
index 0000000..85be1b1
--- /dev/null
+++ b/hw/arm/bcm2835_platform.h
@@ -0,0 +1,230 @@
+/*
+ * arch/arm/mach-bcm2708/include/mach/platform.h
+ *
+ * Copyright (C) 2010 Broadcom
+ *
+ * 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
+ */
+
+#ifndef _BCM2708_PLATFORM_H
+#define _BCM2708_PLATFORM_H
+
+
+/* macros to get at IO space when running virtually */
+#define IO_ADDRESS(x) \
+        (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
+
+#define __io_address(a)     __io(IO_ADDRESS(a))
+
+/*
+ *  SDRAM
+ */
+#define BCM2708_SDRAM_BASE           0x00000000
+
+/*
+ *  Logic expansion modules
+ *
+ */
+
+/* ------------------------------------------------------------------------
+ *  BCM2708 ARMCTRL Registers
+ * ------------------------------------------------------------------------
+ */
+
+#define HW_REGISTER_RW(addr) (addr)
+#define HW_REGISTER_RO(addr) (addr)
+
+#include "bcm2835_arm_control.h"
+#undef ARM_BASE
+
+/*
+ * Definitions and addresses for the ARM CONTROL logic
+ * This file is manually generated.
+ */
+
+#define BCM2708_PERI_BASE              0x20000000
+#define IC0_BASE   (BCM2708_PERI_BASE + 0x2000)
+#define ST_BASE    (BCM2708_PERI_BASE + 0x3000)   /* System Timer */
+#define MPHI_BASE  (BCM2708_PERI_BASE + 0x6000)   /* Message -based Parallel
+                                                   * Host Interface */
+#define DMA_BASE   (BCM2708_PERI_BASE + 0x7000)   /* DMA controller */
+#define ARM_BASE   (BCM2708_PERI_BASE + 0xB000)   /* BCM2708 ARM ctrl block */
+#define PM_BASE    (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset
+                                                   * controller and Watchdog
+                                                   * registers */
+#define GPIO_BASE  (BCM2708_PERI_BASE + 0x200000) /* GPIO */
+#define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */
+#define MMCI0_BASE (BCM2708_PERI_BASE + 0x202000) /* MMC interface */
+#define SPI0_BASE  (BCM2708_PERI_BASE + 0x204000) /* SPI0 */
+#define BSC0_BASE  (BCM2708_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */
+#define UART1_BASE (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
+#define EMMC_BASE  (BCM2708_PERI_BASE + 0x300000) /* eMMC interface */
+#define SMI_BASE   (BCM2708_PERI_BASE + 0x600000) /* SMI */
+#define BSC1_BASE  (BCM2708_PERI_BASE + 0x804000) /* BSC1 I2C/TWI */
+#define USB_BASE   (BCM2708_PERI_BASE + 0x980000) /* DTC_OTG USB controller */
+#define MCORE_BASE (BCM2708_PERI_BASE + 0x0000)   /* Fake frame buffer device
+                                                   * (actually the multicore
+                                                   * sync block */
+
+#define ARMCTRL_BASE          (ARM_BASE + 0x000)
+#define ARMCTRL_IC_BASE       (ARM_BASE + 0x200) /* ARM interrupt controller */
+#define ARMCTRL_TIMER0_1_BASE (ARM_BASE + 0x400) /* Timer 0 and 1 */
+#define ARMCTRL_0_SBM_BASE    (ARM_BASE + 0x800) /* User 0 (ARM)'s Semaphores,
+                                                  * Doorbells and Mailboxes */
+
+
+/*
+ * Interrupt assignments
+ */
+
+#define ARM_IRQ1_BASE                  0
+#define INTERRUPT_TIMER0               (ARM_IRQ1_BASE + 0)
+#define INTERRUPT_TIMER1               (ARM_IRQ1_BASE + 1)
+#define INTERRUPT_TIMER2               (ARM_IRQ1_BASE + 2)
+#define INTERRUPT_TIMER3               (ARM_IRQ1_BASE + 3)
+#define INTERRUPT_CODEC0               (ARM_IRQ1_BASE + 4)
+#define INTERRUPT_CODEC1               (ARM_IRQ1_BASE + 5)
+#define INTERRUPT_CODEC2               (ARM_IRQ1_BASE + 6)
+#define INTERRUPT_VC_JPEG              (ARM_IRQ1_BASE + 7)
+#define INTERRUPT_ISP                  (ARM_IRQ1_BASE + 8)
+#define INTERRUPT_VC_USB               (ARM_IRQ1_BASE + 9)
+#define INTERRUPT_VC_3D                (ARM_IRQ1_BASE + 10)
+#define INTERRUPT_TRANSPOSER           (ARM_IRQ1_BASE + 11)
+#define INTERRUPT_MULTICORESYNC0       (ARM_IRQ1_BASE + 12)
+#define INTERRUPT_MULTICORESYNC1       (ARM_IRQ1_BASE + 13)
+#define INTERRUPT_MULTICORESYNC2       (ARM_IRQ1_BASE + 14)
+#define INTERRUPT_MULTICORESYNC3       (ARM_IRQ1_BASE + 15)
+#define INTERRUPT_DMA0                 (ARM_IRQ1_BASE + 16)
+#define INTERRUPT_DMA1                 (ARM_IRQ1_BASE + 17)
+#define INTERRUPT_VC_DMA2              (ARM_IRQ1_BASE + 18)
+#define INTERRUPT_VC_DMA3              (ARM_IRQ1_BASE + 19)
+#define INTERRUPT_DMA4                 (ARM_IRQ1_BASE + 20)
+#define INTERRUPT_DMA5                 (ARM_IRQ1_BASE + 21)
+#define INTERRUPT_DMA6                 (ARM_IRQ1_BASE + 22)
+#define INTERRUPT_DMA7                 (ARM_IRQ1_BASE + 23)
+#define INTERRUPT_DMA8                 (ARM_IRQ1_BASE + 24)
+#define INTERRUPT_DMA9                 (ARM_IRQ1_BASE + 25)
+#define INTERRUPT_DMA10                (ARM_IRQ1_BASE + 26)
+#define INTERRUPT_DMA11                (ARM_IRQ1_BASE + 27)
+#define INTERRUPT_DMA12                (ARM_IRQ1_BASE + 28)
+#define INTERRUPT_AUX                  (ARM_IRQ1_BASE + 29)
+#define INTERRUPT_ARM                  (ARM_IRQ1_BASE + 30)
+#define INTERRUPT_VPUDMA               (ARM_IRQ1_BASE + 31)
+
+#define ARM_IRQ2_BASE                  32
+#define INTERRUPT_HOSTPORT             (ARM_IRQ2_BASE + 0)
+#define INTERRUPT_VIDEOSCALER          (ARM_IRQ2_BASE + 1)
+#define INTERRUPT_CCP2TX               (ARM_IRQ2_BASE + 2)
+#define INTERRUPT_SDC                  (ARM_IRQ2_BASE + 3)
+#define INTERRUPT_DSI0                 (ARM_IRQ2_BASE + 4)
+#define INTERRUPT_AVE                  (ARM_IRQ2_BASE + 5)
+#define INTERRUPT_CAM0                 (ARM_IRQ2_BASE + 6)
+#define INTERRUPT_CAM1                 (ARM_IRQ2_BASE + 7)
+#define INTERRUPT_HDMI0                (ARM_IRQ2_BASE + 8)
+#define INTERRUPT_HDMI1                (ARM_IRQ2_BASE + 9)
+#define INTERRUPT_PIXELVALVE1          (ARM_IRQ2_BASE + 10)
+#define INTERRUPT_I2CSPISLV            (ARM_IRQ2_BASE + 11)
+#define INTERRUPT_DSI1                 (ARM_IRQ2_BASE + 12)
+#define INTERRUPT_PWA0                 (ARM_IRQ2_BASE + 13)
+#define INTERRUPT_PWA1                 (ARM_IRQ2_BASE + 14)
+#define INTERRUPT_CPR                  (ARM_IRQ2_BASE + 15)
+#define INTERRUPT_SMI                  (ARM_IRQ2_BASE + 16)
+#define INTERRUPT_GPIO0                (ARM_IRQ2_BASE + 17)
+#define INTERRUPT_GPIO1                (ARM_IRQ2_BASE + 18)
+#define INTERRUPT_GPIO2                (ARM_IRQ2_BASE + 19)
+#define INTERRUPT_GPIO3                (ARM_IRQ2_BASE + 20)
+#define INTERRUPT_VC_I2C               (ARM_IRQ2_BASE + 21)
+#define INTERRUPT_VC_SPI               (ARM_IRQ2_BASE + 22)
+#define INTERRUPT_VC_I2SPCM            (ARM_IRQ2_BASE + 23)
+#define INTERRUPT_VC_SDIO              (ARM_IRQ2_BASE + 24)
+#define INTERRUPT_VC_UART              (ARM_IRQ2_BASE + 25)
+#define INTERRUPT_SLIMBUS              (ARM_IRQ2_BASE + 26)
+#define INTERRUPT_VEC                  (ARM_IRQ2_BASE + 27)
+#define INTERRUPT_CPG                  (ARM_IRQ2_BASE + 28)
+#define INTERRUPT_RNG                  (ARM_IRQ2_BASE + 29)
+#define INTERRUPT_VC_ARASANSDIO        (ARM_IRQ2_BASE + 30)
+#define INTERRUPT_AVSPMON              (ARM_IRQ2_BASE + 31)
+
+#define ARM_IRQ0_BASE                  64
+#define INTERRUPT_ARM_TIMER            (ARM_IRQ0_BASE + 0)
+#define INTERRUPT_ARM_MAILBOX          (ARM_IRQ0_BASE + 1)
+#define INTERRUPT_ARM_DOORBELL_0       (ARM_IRQ0_BASE + 2)
+#define INTERRUPT_ARM_DOORBELL_1       (ARM_IRQ0_BASE + 3)
+#define INTERRUPT_VPU0_HALTED          (ARM_IRQ0_BASE + 4)
+#define INTERRUPT_VPU1_HALTED          (ARM_IRQ0_BASE + 5)
+#define INTERRUPT_ILLEGAL_TYPE0        (ARM_IRQ0_BASE + 6)
+#define INTERRUPT_ILLEGAL_TYPE1        (ARM_IRQ0_BASE + 7)
+#define INTERRUPT_PENDING1             (ARM_IRQ0_BASE + 8)
+#define INTERRUPT_PENDING2             (ARM_IRQ0_BASE + 9)
+#define INTERRUPT_JPEG                 (ARM_IRQ0_BASE + 10)
+#define INTERRUPT_USB                  (ARM_IRQ0_BASE + 11)
+#define INTERRUPT_3D                   (ARM_IRQ0_BASE + 12)
+#define INTERRUPT_DMA2                 (ARM_IRQ0_BASE + 13)
+#define INTERRUPT_DMA3                 (ARM_IRQ0_BASE + 14)
+#define INTERRUPT_I2C                  (ARM_IRQ0_BASE + 15)
+#define INTERRUPT_SPI                  (ARM_IRQ0_BASE + 16)
+#define INTERRUPT_I2SPCM               (ARM_IRQ0_BASE + 17)
+#define INTERRUPT_SDIO                 (ARM_IRQ0_BASE + 18)
+#define INTERRUPT_UART                 (ARM_IRQ0_BASE + 19)
+#define INTERRUPT_ARASANSDIO           (ARM_IRQ0_BASE + 20)
+
+#define MAXIRQNUM                      (32 + 32 + 20)
+#define MAXFIQNUM                      (32 + 32 + 20)
+
+#define MAX_TIMER                      2
+#define MAX_PERIOD                     699050
+#define TICKS_PER_uSEC                 1
+
+/*
+ *  These are useconds NOT ticks.
+ *
+ */
+#define mSEC_1                         1000
+#define mSEC_5                         (mSEC_1 * 5)
+#define mSEC_10                        (mSEC_1 * 10)
+#define mSEC_25                        (mSEC_1 * 25)
+#define SEC_1                          (mSEC_1 * 1000)
+
+/*
+ * Watchdog
+ */
+#define PM_RSTC                        (PM_BASE+0x1c)
+#define PM_RSTS                        (PM_BASE+0x20)
+#define PM_WDOG                        (PM_BASE+0x24)
+
+#define PM_WDOG_RESET                  0x00000000
+#define PM_PASSWORD                    0x5a000000
+#define PM_WDOG_TIME_SET               0x000fffff
+#define PM_RSTC_WRCFG_CLR              0xffffffcf
+#define PM_RSTC_WRCFG_SET              0x00000030
+#define PM_RSTC_WRCFG_FULL_RESET       0x00000020
+#define PM_RSTC_RESET                  0x00000102
+
+#define PM_RSTS_HADPOR_SET             0x00001000
+#define PM_RSTS_HADSRH_SET             0x00000400
+#define PM_RSTS_HADSRF_SET             0x00000200
+#define PM_RSTS_HADSRQ_SET             0x00000100
+#define PM_RSTS_HADWRH_SET             0x00000040
+#define PM_RSTS_HADWRF_SET             0x00000020
+#define PM_RSTS_HADWRQ_SET             0x00000010
+#define PM_RSTS_HADDRH_SET             0x00000004
+#define PM_RSTS_HADDRF_SET             0x00000002
+#define PM_RSTS_HADDRQ_SET             0x00000001
+
+#define UART0_CLOCK                    3000000
+
+#endif
+
+/* END */
diff --git a/hw/arm/bcm2835_power.c b/hw/arm/bcm2835_power.c
new file mode 100644
index 0000000..48c90c5
--- /dev/null
+++ b/hw/arm/bcm2835_power.c
@@ -0,0 +1,117 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+
+#include "bcm2835_common.h"
+
+#define TYPE_BCM2835_POWER "bcm2835_power"
+#define BCM2835_POWER(obj) \
+        OBJECT_CHECK(bcm2835_power_state, (obj), TYPE_BCM2835_POWER)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    int pending;
+    qemu_irq mbox_irq;
+} bcm2835_power_state;
+
+static uint64_t bcm2835_power_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_power_state *s = (bcm2835_power_state *)opaque;
+    uint32_t res = 0;
+
+    switch (offset) {
+    case 0:
+        res = MBOX_CHAN_POWER;
+        s->pending = 0;
+        qemu_set_irq(s->mbox_irq, 0);
+        break;
+    case 4:
+        res = s->pending;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_power_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+    return res;
+}
+static void bcm2835_power_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+    bcm2835_power_state *s = (bcm2835_power_state *)opaque;
+    switch (offset) {
+    case 0:
+        s->pending = 1;
+        qemu_set_irq(s->mbox_irq, 1);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_power_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+
+}
+
+
+static const MemoryRegionOps bcm2835_power_ops = {
+    .read = bcm2835_power_read,
+    .write = bcm2835_power_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+
+static const VMStateDescription vmstate_bcm2835_power = {
+    .name = "bcm2835_power",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_power_init(SysBusDevice *sbd)
+{
+    /* bcm2835_power_state *s = FROM_SYSBUS(bcm2835_power_state, dev); */
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_power_state *s = BCM2835_POWER(dev);
+
+    s->pending = 0;
+
+    sysbus_init_irq(sbd, &s->mbox_irq);
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_power_ops, s,
+        "bcm2835_power", 0x10);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_power, s);
+
+    return 0;
+}
+
+static void bcm2835_power_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    /* DeviceClass *k = DEVICE_CLASS(klass); */
+
+    sdc->init = bcm2835_power_init;
+}
+
+static TypeInfo bcm2835_power_info = {
+    .name          = "bcm2835_power",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_power_state),
+    .class_init    = bcm2835_power_class_init,
+};
+
+static void bcm2835_power_register_types(void)
+{
+    type_register_static(&bcm2835_power_info);
+}
+
+type_init(bcm2835_power_register_types)
diff --git a/hw/arm/bcm2835_property.c b/hw/arm/bcm2835_property.c
new file mode 100644
index 0000000..8a82fd2
--- /dev/null
+++ b/hw/arm/bcm2835_property.c
@@ -0,0 +1,413 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+#include "ui/console.h"
+#include "hw/display/framebuffer.h"
+#include "ui/pixel_ops.h"
+
+#include "bcm2835_common.h"
+
+/* #define LOG_REG_ACCESS */
+
+#define TYPE_BCM2835_PROPERTY "bcm2835_property"
+#define BCM2835_PROPERTY(obj) \
+        OBJECT_CHECK(bcm2835_property_state, (obj), TYPE_BCM2835_PROPERTY)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    int pending;
+    qemu_irq mbox_irq;
+
+    uint32_t addr;
+} bcm2835_property_state;
+
+static void update_fb(void)
+{
+    bcm2835_fb.lock = 1;
+
+    bcm2835_fb.base = bcm2835_vcram_base;
+    bcm2835_fb.base += BCM2835_FB_OFFSET;
+
+    /* TODO - Manage properly virtual resolution */
+
+    bcm2835_fb.pitch = bcm2835_fb.xres * (bcm2835_fb.bpp >> 3);
+    bcm2835_fb.size = bcm2835_fb.yres * bcm2835_fb.pitch;
+}
+
+
+static void bcm2835_property_mbox_push(bcm2835_property_state *s,
+    uint32_t value)
+{
+#ifdef LOG_REG_ACCESS
+    uint32_t size;
+#endif
+    uint32_t tag;
+    uint32_t bufsize;
+    int n;
+    int resplen;
+    uint32_t offset, length, color;
+
+    value &= ~0xf;
+    s->addr = value;
+
+#ifdef LOG_REG_ACCESS
+    size = ldl_phys(s->addr);
+    printf("=== PROPERTY MBOX PUSH BEGIN addr=%08x\n", s->addr);
+    printf("Request:\n");
+    for (n = 0; n < size; n += 4) {
+        printf("[%08x] ", ldl_phys(s->addr + n));
+        if (((n >> 2) & 7) == 7) {
+            printf("\n");
+        }
+    }
+    printf("\n");
+#endif
+
+    /* @(s->addr + 4) : Buffer response code */
+    value = s->addr + 8;
+    do {
+        tag = ldl_phys(value);
+        bufsize = ldl_phys(value + 4);
+        /* @(value + 8) : Request/response indicator */
+#ifdef LOG_REG_ACCESS
+        printf("TAG [%08x]\n", tag);
+#endif
+        resplen = 0;
+        switch (tag) {
+        case 0x00000000: /* End tag */
+            break;
+        case 0x00000001: /* Get firmware revision */
+            stl_phys(value + 12, 346337);
+            resplen = 4;
+            break;
+
+        case 0x00010001: /* Get board model */
+            resplen = 4;
+            break;
+        case 0x00010002: /* Get board revision */
+            resplen = 4;
+            break;
+        case 0x00010003: /* Get board MAC address */
+            stl_phys(value + 12, 0xB827EBD0);
+            stl_phys(value + 16, 0xEEDF0000);
+            resplen = 6;
+            break;
+        case 0x00010004: /* Get board serial */
+            resplen = 8;
+            break;
+        case 0x00010005: /* Get ARM memory */
+            stl_phys(value + 12, 0); /* base */
+            stl_phys(value + 16, bcm2835_vcram_base); /* size */
+            resplen = 8;
+            break;
+        case 0x00010006: /* Get VC memory */
+            stl_phys(value + 12, bcm2835_vcram_base); /* base */
+            stl_phys(value + 16, VCRAM_SIZE); /* size */
+            resplen = 8;
+            break;
+
+        /* Clocks */
+
+        case 0x00030001: /* Get clock state */
+            stl_phys(value + 16, 0x1);
+            resplen = 8;
+            break;
+
+        case 0x00038001: /* Set clock state */
+            resplen = 8;
+            break;
+
+        case 0x00030002: /* Get clock rate */
+        case 0x00030004: /* Get max clock rate */
+        case 0x00030007: /* Get min clock rate */
+            switch (ldl_phys(value + 12)) {
+            case 1: /* EMMC */
+                stl_phys(value + 16, 50000000);
+                break;
+            case 2: /* UART */
+                stl_phys(value + 16, 3000000);
+                break;
+            default:
+                stl_phys(value + 16, 700000000);
+                break;
+            }
+            resplen = 8;
+            break;
+
+        case 0x00038002: /* Set clock rate */
+        case 0x00038004: /* Set max clock rate */
+        case 0x00038007: /* Set min clock rate */
+            resplen = 8;
+            break;
+
+        /* Temperature */
+
+        case 0x00030006: /* Get temperature */
+            stl_phys(value + 16, 25000);
+            resplen = 8;
+            break;
+
+        case 0x0003000A: /* Get max temperature */
+            stl_phys(value + 16, 99000);
+            resplen = 8;
+            break;
+
+
+        /* Frame buffer */
+
+        case 0x00040001: /* Allocate buffer */
+            stl_phys(value + 12, bcm2835_fb.base); /* base */
+            stl_phys(value + 16, bcm2835_fb.size); /* size */
+            resplen = 8;
+            break;
+        case 0x00048001: /* Release buffer */
+            resplen = 0;
+            break;
+        case 0x00040002: /* Blank screen */
+            resplen = 4;
+            break;
+        case 0x00040003: /* Get display width/height */
+        case 0x00040004:
+            stl_phys(value + 12, bcm2835_fb.xres);
+            stl_phys(value + 16, bcm2835_fb.yres);
+            resplen = 8;
+            break;
+        case 0x00044003: /* Test display width/height */
+        case 0x00044004:
+            resplen = 8;
+            break;
+        case 0x00048003: /* Set display width/height */
+        case 0x00048004:
+            bcm2835_fb.xres = ldl_phys(value + 12);
+            bcm2835_fb.yres = ldl_phys(value + 16);
+            update_fb();
+            resplen = 8;
+            break;
+        case 0x00040005: /* Get depth */
+            stl_phys(value + 12, bcm2835_fb.bpp);
+            resplen = 4;
+            break;
+        case 0x00044005: /* Test depth */
+            resplen = 4;
+            break;
+        case 0x00048005: /* Set depth */
+            bcm2835_fb.bpp = ldl_phys(value + 12);
+            update_fb();
+            resplen = 4;
+            break;
+        case 0x00040006: /* Get pixel order */
+            stl_phys(value + 12, bcm2835_fb.pixo);
+            resplen = 4;
+            break;
+        case 0x00044006: /* Test pixel order */
+            resplen = 4;
+            break;
+        case 0x00048006: /* Set pixel order */
+            bcm2835_fb.pixo = ldl_phys(value + 12);
+            update_fb();
+            resplen = 4;
+            break;
+        case 0x00040007: /* Get alpha */
+            stl_phys(value + 12, bcm2835_fb.alpha);
+            resplen = 4;
+            break;
+        case 0x00044007: /* Test pixel alpha */
+            resplen = 4;
+            break;
+        case 0x00048007: /* Set alpha */
+            bcm2835_fb.alpha = ldl_phys(value + 12);
+            update_fb();
+            resplen = 4;
+            break;
+        case 0x00040008: /* Get pitch */
+            stl_phys(value + 12, bcm2835_fb.pitch);
+            resplen = 4;
+            break;
+        case 0x00040009: /* Get virtual offset */
+            stl_phys(value + 12, bcm2835_fb.xoffset);
+            stl_phys(value + 16, bcm2835_fb.yoffset);
+            resplen = 8;
+            break;
+        case 0x00044009: /* Test virtual offset */
+            resplen = 8;
+            break;
+        case 0x00048009: /* Set virtual offset */
+            bcm2835_fb.xoffset = ldl_phys(value + 12);
+            bcm2835_fb.yoffset = ldl_phys(value + 16);
+            update_fb();
+            stl_phys(value + 12, bcm2835_fb.xres);
+            stl_phys(value + 16, bcm2835_fb.yres);
+            resplen = 8;
+            break;
+        case 0x0004000a: /* Get/Test/Set overscan */
+        case 0x0004400a:
+        case 0x0004800a:
+            stl_phys(value + 12, 0);
+            stl_phys(value + 16, 0);
+            stl_phys(value + 20, 0);
+            stl_phys(value + 24, 0);
+            resplen = 16;
+            break;
+
+        case 0x0004800b: /* Set palette */
+            offset = ldl_phys(value + 12);
+            length = ldl_phys(value + 16);
+            n = 0;
+            while (n < length - offset) {
+                color = ldl_phys(value + 20 + (n << 2));
+                stl_phys(bcm2835_vcram_base + ((offset + n) << 2), color);
+                n++;
+            }
+            stl_phys(value + 12, 0);
+            resplen = 4;
+            break;
+
+        case 0x00060001: /* Get DMA channels */
+            stl_phys(value + 12, 0x003C); /* channels 2-5 */
+            resplen = 4;
+            break;
+
+        case 0x00050001: /* Get command line */
+            resplen = 0;
+            break;
+
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR,
+                "bcm2835_property: unhandled tag %08x\n", tag);
+            break;
+        }
+        if (tag != 0) {
+            stl_phys(value + 8, (1 << 31) | resplen);
+        }
+
+        value += bufsize + 12;
+    } while (tag != 0);
+
+    /* Buffer response code */
+    stl_phys(s->addr + 4, (1 << 31));
+
+#ifdef LOG_REG_ACCESS
+    printf("Response:\n");
+    for (n = 0; n < size; n += 4) {
+        printf("[%08x] ", ldl_phys(s->addr + n));
+        if (((n >> 2) & 7) == 7) {
+            printf("\n");
+        }
+    }
+    printf("\n");
+    printf("=== PROPERTY MBOX PUSH END\n");
+#endif
+
+    if (bcm2835_fb.lock) {
+        bcm2835_fb.invalidate = 1;
+        qemu_console_resize(bcm2835_fb.con, bcm2835_fb.xres, bcm2835_fb.yres);
+        bcm2835_fb.lock = 0;
+    }
+}
+
+static uint64_t bcm2835_property_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_property_state *s = (bcm2835_property_state *)opaque;
+    uint32_t res = 0;
+
+    switch (offset) {
+    case 0:
+        res = MBOX_CHAN_PROPERTY | s->addr;
+        s->pending = 0;
+        qemu_set_irq(s->mbox_irq, 0);
+        break;
+    case 4:
+        res = s->pending;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_property_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+    return res;
+}
+static void bcm2835_property_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+    bcm2835_property_state *s = (bcm2835_property_state *)opaque;
+    switch (offset) {
+    case 0:
+        if (!s->pending) {
+            s->pending = 1;
+            bcm2835_property_mbox_push(s, value);
+            qemu_set_irq(s->mbox_irq, 1);
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_property_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+
+}
+
+
+static const MemoryRegionOps bcm2835_property_ops = {
+    .read = bcm2835_property_read,
+    .write = bcm2835_property_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+
+static const VMStateDescription vmstate_bcm2835_property = {
+    .name = "bcm2835_property",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_property_init(SysBusDevice *sbd)
+{
+    /* bcm2835_property_state *s = FROM_SYSBUS(bcm2835_property_state, dev); */
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_property_state *s = BCM2835_PROPERTY(dev);
+
+    s->pending = 0;
+    s->addr = 0;
+
+    sysbus_init_irq(sbd, &s->mbox_irq);
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s,
+        "bcm2835_property", 0x10);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_property, s);
+
+    return 0;
+}
+
+static void bcm2835_property_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    /* DeviceClass *k = DEVICE_CLASS(klass); */
+
+    sdc->init = bcm2835_property_init;
+}
+
+static TypeInfo bcm2835_property_info = {
+    .name          = "bcm2835_property",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_property_state),
+    .class_init    = bcm2835_property_class_init,
+};
+
+static void bcm2835_property_register_types(void)
+{
+    type_register_static(&bcm2835_property_info);
+}
+
+type_init(bcm2835_property_register_types)
diff --git a/hw/arm/bcm2835_sbm.c b/hw/arm/bcm2835_sbm.c
new file mode 100644
index 0000000..7608c2c
--- /dev/null
+++ b/hw/arm/bcm2835_sbm.c
@@ -0,0 +1,293 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+
+#include "bcm2835_common.h"
+
+#define TYPE_BCM2835_SBM "bcm2835_sbm"
+#define BCM2835_SBM(obj) \
+        OBJECT_CHECK(bcm2835_sbm_state, (obj), TYPE_BCM2835_SBM)
+
+typedef struct {
+    uint32_t reg[MBOX_SIZE];
+    int count;
+    uint32_t status;
+    uint32_t config;
+} bcm2835_mbox;
+
+
+static void mbox_update_status(bcm2835_mbox *mb)
+{
+    if (mb->count == 0) {
+        mb->status |= ARM_MS_EMPTY;
+    } else {
+        mb->status &= ~ARM_MS_EMPTY;
+    }
+    if (mb->count == MBOX_SIZE) {
+        mb->status |= ARM_MS_FULL;
+    } else {
+        mb->status &= ~ARM_MS_FULL;
+    }
+}
+
+static void mbox_init(bcm2835_mbox *mb)
+{
+    int n;
+    mb->count = 0;
+    mb->config = 0;
+    for (n = 0; n < MBOX_SIZE; n++) {
+        mb->reg[n] = MBOX_INVALID_DATA;
+    }
+    mbox_update_status(mb);
+}
+
+static uint32_t mbox_pull(bcm2835_mbox *mb, int index)
+{
+    int n;
+    uint32_t val;
+
+    assert(mb->count > 0);
+    assert(index < mb->count);
+
+    val = mb->reg[index];
+    for (n = index + 1; n < mb->count; n++) {
+        mb->reg[n - 1] = mb->reg[n];
+    }
+    mb->count--;
+    mb->reg[mb->count] = MBOX_INVALID_DATA;
+
+    mbox_update_status(mb);
+
+    return val;
+}
+
+static void mbox_push(bcm2835_mbox *mb, uint32_t val)
+{
+
+    assert(mb->count < MBOX_SIZE);
+
+    mb->reg[mb->count++] = val;
+
+    mbox_update_status(mb);
+}
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    int mbox_irq_disabled;
+    qemu_irq arm_irq;
+    int available[MBOX_CHAN_COUNT];
+    bcm2835_mbox mbox[2];
+
+} bcm2835_sbm_state;
+
+static void bcm2835_sbm_update(bcm2835_sbm_state *s)
+{
+    int set;
+    int done, n;
+    uint32_t value;
+
+    /* Avoid unwanted recursive calls */
+    s->mbox_irq_disabled = 1;
+
+    /* Get pending responses and put them in the vc->arm mbox */
+    done = 0;
+    while (!done) {
+        done = 1;
+        if (s->mbox[0].status & ARM_MS_FULL) {
+            /* vc->arm mbox full, exit */
+        } else {
+            for (n = 0; n < MBOX_CHAN_COUNT; n++) {
+                if (s->available[n]) {
+                    value = ldl_phys(ARMCTRL_0_SBM_BASE + 0x400 + (n<<4));
+                    if (value != MBOX_INVALID_DATA) {
+                        /* printf("AVAIL MBOX PUSH\n"); */
+                        mbox_push(&s->mbox[0], value);
+                    } else {
+                        /* Hmmm... */
+                    }
+                    done = 0;
+                    break;
+                }
+            }
+        }
+    }
+
+    /* Try to push pending requests from the arm->vc mbox */
+    /* TODO (?) */
+
+    /* Re-enable calls from the IRQ routine */
+    s->mbox_irq_disabled = 0;
+
+    /* Update ARM IRQ status */
+    set = 0;
+    if (s->mbox[0].config & ARM_MC_IHAVEDATAIRQEN) {
+        if (!(s->mbox[0].status & ARM_MS_EMPTY)) {
+            set = 1;
+        }
+    }
+    qemu_set_irq(s->arm_irq, set);
+}
+
+static void bcm2835_sbm_set_irq(void *opaque, int irq, int level)
+{
+    bcm2835_sbm_state *s = (bcm2835_sbm_state *)opaque;
+    /* printf("SBM MBOX IRQ %d = %d\n", irq, level); */
+    s->available[irq] = level;
+    if (!s->mbox_irq_disabled) {
+        bcm2835_sbm_update(s);
+    }
+}
+
+static uint64_t bcm2835_sbm_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    bcm2835_sbm_state *s = (bcm2835_sbm_state *)opaque;
+    uint32_t res = 0;
+
+    offset &= 0xff;
+
+    switch (offset) {
+    case 0x80:  /* MAIL0_READ */
+    case 0x84:
+    case 0x88:
+    case 0x8c:
+        if (s->mbox[0].status & ARM_MS_EMPTY) {
+            res = MBOX_INVALID_DATA;
+        } else {
+            res = mbox_pull(&s->mbox[0], 0);
+        }
+        break;
+    case 0x90:  /* MAIL0_PEEK */
+        res = s->mbox[0].reg[0];
+        break;
+    case 0x94:  /* MAIL0_SENDER */
+        break;
+    case 0x98:  /* MAIL0_STATUS */
+        res = s->mbox[0].status;
+        break;
+    case 0x9c:  /* MAIL0_CONFIG */
+        res = s->mbox[0].config;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_sbm_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+
+    bcm2835_sbm_update(s);
+
+    return res;
+}
+
+static void bcm2835_sbm_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    int ch;
+
+    bcm2835_sbm_state *s = (bcm2835_sbm_state *)opaque;
+
+    offset &= 0xff;
+
+    switch (offset) {
+    case 0x94:  /* MAIL0_SENDER */
+        break;
+    case 0x9c:  /* MAIL0_CONFIG */
+        s->mbox[0].config = value & ARM_MC_IHAVEDATAIRQEN;
+        break;
+    case 0xa0:
+    case 0xa4:
+    case 0xa8:
+    case 0xac:
+        if (s->mbox[1].status & ARM_MS_FULL) {
+            /* Guest error */
+        } else {
+            ch = value & 0xf;
+            if (ch < MBOX_CHAN_COUNT) {
+                if (ldl_phys(ARMCTRL_0_SBM_BASE + 0x400 + (ch<<4) + 4)) {
+                    /* Push delayed, push it in the arm->vc mbox */
+                    mbox_push(&s->mbox[1], value);
+                } else {
+                    stl_phys(ARMCTRL_0_SBM_BASE + 0x400 + (ch<<4), value);
+                }
+            } else {
+                /* Invalid channel number */
+            }
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_sbm_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+
+    bcm2835_sbm_update(s);
+}
+
+static const MemoryRegionOps bcm2835_sbm_ops = {
+    .read = bcm2835_sbm_read,
+    .write = bcm2835_sbm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_bcm2835_sbm = {
+    .name = "bcm2835_sbm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_sbm_init(SysBusDevice *sbd)
+{
+    /* bcm2835_sbm_state *s = FROM_SYSBUS(bcm2835_sbm_state, dev); */
+    int n;
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_sbm_state *s = BCM2835_SBM(dev);
+
+    mbox_init(&s->mbox[0]);
+    mbox_init(&s->mbox[1]);
+    s->mbox_irq_disabled = 0;
+    for (n = 0; n < MBOX_CHAN_COUNT; n++) {
+        s->available[n] = 0;
+    }
+
+    sysbus_init_irq(sbd, &s->arm_irq);
+    qdev_init_gpio_in(dev, bcm2835_sbm_set_irq, MBOX_CHAN_COUNT);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_sbm_ops, s,
+        "bcm2835_sbm", 0x400);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_sbm, s);
+
+    return 0;
+}
+
+static void bcm2835_sbm_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    /* DeviceClass *k = DEVICE_CLASS(klass); */
+
+    sdc->init = bcm2835_sbm_init;
+}
+
+static TypeInfo bcm2835_sbm_info = {
+    .name          = "bcm2835_sbm",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_sbm_state),
+    .class_init    = bcm2835_sbm_class_init,
+};
+
+static void bcm2835_sbm_register_types(void)
+{
+    type_register_static(&bcm2835_sbm_info);
+}
+
+type_init(bcm2835_sbm_register_types)
diff --git a/hw/arm/bcm2835_st.c b/hw/arm/bcm2835_st.c
new file mode 100644
index 0000000..2bc86d7
--- /dev/null
+++ b/hw/arm/bcm2835_st.c
@@ -0,0 +1,218 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+/* Based on several timers code found in various QEMU source files. */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+
+/* #define LOG_REG_ACCESS */
+
+#define TYPE_BCM2835_ST "bcm2835_st"
+#define BCM2835_ST(obj) OBJECT_CHECK(bcm2835_st_state, (obj), TYPE_BCM2835_ST)
+
+typedef struct bcm2835_st_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    QEMUTimer *timer;
+    uint32_t compare[4];
+    uint32_t match;
+    uint32_t next;
+    qemu_irq irq[4];
+} bcm2835_st_state;
+
+static void bcm2835_st_update(bcm2835_st_state *s)
+{
+    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / SCALE_US;
+    uint32_t clo = (uint32_t)now;
+    uint32_t delta = -1;
+    int i;
+
+    /* Calculate new "next" value and reschedule */
+    for (i = 0; i < 4; i++) {
+        if (!(s->match & (1 << i))) {
+            if (s->compare[i] - clo < delta) {
+                s->next = s->compare[i];
+                delta = s->next - clo;
+            }
+        }
+    }
+    timer_mod(s->timer, now + delta);
+}
+
+static void bcm2835_st_tick(void *opaque)
+{
+    bcm2835_st_state *s = (bcm2835_st_state *)opaque;
+    int i;
+
+    /* Trigger irqs for current "next" value */
+    for (i = 0; i < 4; i++) {
+        if (!(s->match & (1 << i)) && (s->next == s->compare[i])) {
+            s->match |= (1 << i);
+            /* printf("irq %d\n", i); */
+            qemu_set_irq(s->irq[i], 1);
+        }
+    }
+
+    bcm2835_st_update(s);
+}
+
+static uint64_t bcm2835_st_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    bcm2835_st_state *s = (bcm2835_st_state *)opaque;
+    uint32_t res = 0;
+    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / SCALE_US;
+
+    assert(size == 4);
+
+    switch (offset) {
+    case 0x00:
+        res = s->match;
+        break;
+    case 0x04:
+        res = (uint32_t)now;
+        /* Ugly temporary hack to get Plan9 to boot... */
+         * miller/rpi/sys/src/9/bcm/clock.c */
+        /* res = (now / 10000) * 10000; */
+        break;
+    case 0x08:
+        res = (now >> 32);
+        break;
+    case 0x0c:
+        res = s->compare[0];
+        break;
+    case 0x10:
+        res = s->compare[1];
+        break;
+    case 0x14:
+        res = s->compare[2];
+        break;
+    case 0x18:
+        res = s->compare[3];
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_st_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_st: read(%x) %08x\n", (int)offset, res);
+#endif
+
+    return res;
+}
+
+static void bcm2835_st_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    bcm2835_st_state *s = (bcm2835_st_state *)opaque;
+    int i;
+
+    assert(size == 4);
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_st: write(%x) %08x\n", (int)offset,
+        (uint32_t)value);
+#endif
+
+
+    switch (offset) {
+    case 0x00:
+        s->match &= ~value & 0x0f;
+        for (i = 0; i < 4; i++) {
+            if (!(s->match & (1 << i))) {
+                qemu_set_irq(s->irq[i], 0);
+            }
+        }
+        break;
+    case 0x0c:
+        s->compare[0] = value;
+        break;
+    case 0x10:
+        s->compare[1] = value;
+        break;
+    case 0x14:
+        s->compare[2] = value;
+        break;
+    case 0x18:
+        s->compare[3] = value;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_st_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+    bcm2835_st_update(s);
+}
+
+static const MemoryRegionOps bcm2835_st_ops = {
+    .read = bcm2835_st_read,
+    .write = bcm2835_st_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_bcm2835_st = {
+    .name = "bcm2835_st",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(compare, bcm2835_st_state, 4),
+        VMSTATE_UINT32(match, bcm2835_st_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_st_init(SysBusDevice *sbd)
+{
+    /* bcm2835_st_state *s = FROM_SYSBUS(bcm2835_st_state, dev); */
+    int i;
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_st_state *s = BCM2835_ST(dev);
+
+    for (i = 0; i < 4; i++) {
+        s->compare[i] = 0;
+        sysbus_init_irq(sbd, &s->irq[i]);
+    }
+    s->match = 0;
+
+    s->timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_US, bcm2835_st_tick, s);
+
+    bcm2835_st_update(s);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_st_ops, s,
+        "bcm2835_st", 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_st, s);
+
+    return 0;
+}
+
+static void bcm2835_st_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    /* DeviceClass *k = DEVICE_CLASS(klass); */
+
+    sdc->init = bcm2835_st_init;
+}
+
+static TypeInfo bcm2835_st_info = {
+    .name          = "bcm2835_st",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_st_state),
+    .class_init    = bcm2835_st_class_init,
+};
+
+static void bcm2835_st_register_types(void)
+{
+    type_register_static(&bcm2835_st_info);
+}
+
+type_init(bcm2835_st_register_types)
diff --git a/hw/arm/bcm2835_timer.c b/hw/arm/bcm2835_timer.c
new file mode 100644
index 0000000..b392ae7
--- /dev/null
+++ b/hw/arm/bcm2835_timer.c
@@ -0,0 +1,260 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "qemu/main-loop.h"
+#include "hw/qdev.h"
+#include "hw/ptimer.h"
+
+/* #define LOG_REG_ACCESS */
+
+#define SYSCLOCK_FREQ (252000000)
+#define APBCLOCK_FREQ (126000000)
+
+#define CTRL_FRC_EN (1 << 9)
+#define CTRL_TIMER_EN (1 << 7)
+#define CTRL_IRQ_EN (1 << 5)
+#define CTRL_PS_MASK (3 << 2)
+#define CTRL_PS_SHIFT 2
+#define CTRL_CNT_32 (1 << 1)
+#define CTRL_FRC_PS_MASK (0xff << 16)
+#define CTRL_FRC_PS_SHIFT 16
+
+#define TYPE_BCM2835_TIMER "bcm2835_timer"
+#define BCM2835_TIMER(obj) \
+        OBJECT_CHECK(bcm2835_timer_state, (obj), TYPE_BCM2835_TIMER)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    qemu_irq irq;
+
+    uint32_t load;
+    uint32_t control;
+    uint32_t raw_irq;
+    uint32_t prediv;
+    uint32_t frc_value;
+
+    ptimer_state *timer;
+    ptimer_state *frc_timer;
+} bcm2835_timer_state;
+
+static void timer_tick(void *opaque)
+{
+    bcm2835_timer_state *s = (bcm2835_timer_state *)opaque;
+    s->raw_irq = 1;
+    if (s->control & CTRL_IRQ_EN) {
+        qemu_set_irq(s->irq, 1);
+    }
+}
+static void frc_timer_tick(void *opaque)
+{
+    bcm2835_timer_state *s = (bcm2835_timer_state *)opaque;
+    s->frc_value++;
+#ifdef LOG_REG_ACCESS
+    /* printf("[QEMU] bcm2835_timer: FRC tick %08x\n", s->frc_value); */
+#endif
+}
+
+static uint64_t bcm2835_timer_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_timer_state *s = (bcm2835_timer_state *)opaque;
+    uint32_t res = 0;
+
+    assert(size == 4);
+
+    switch (offset) {
+    case 0x0:
+        res = s->load;
+        break;
+    case 0x4:
+        res = ptimer_get_count(s->timer);
+        break;
+    case 0x8:
+        res = s->control;
+        break;
+    case 0xc:
+        res = 0x544d5241;
+        break;
+    case 0x10:
+        res = s->raw_irq;
+        break;
+    case 0x14:
+        if (s->control & CTRL_IRQ_EN) {
+            res = s->raw_irq;
+        }
+        break;
+    case 0x18:
+        res = s->load;
+        break;
+    case 0x1c:
+        res = s->prediv;
+        break;
+    case 0x20:
+        res = s->frc_value;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_timer_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_timer: read(%x) %08x\n", (int)offset, res);
+#endif
+
+    return res;
+}
+
+static void bcm2835_timer_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+    bcm2835_timer_state *s = (bcm2835_timer_state *)opaque;
+    uint32_t freq;
+
+    assert(size == 4);
+
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835_timer: write(%x) %08x\n", (int)offset,
+        (uint32_t)value);
+#endif
+
+    switch (offset) {
+    case 0x0:
+        s->load = value;
+        ptimer_set_limit(s->timer, s->load, 1);
+        break;
+    case 0x4:
+        break;
+    case 0x8:
+        if (s->control & CTRL_FRC_EN) {
+            ptimer_stop(s->frc_timer);
+        }
+        if (s->control & CTRL_TIMER_EN) {
+            ptimer_stop(s->timer);
+        }
+        s->control = value & 0x00ff03ae;
+
+        freq = SYSCLOCK_FREQ;
+        /* freq /= ((s->control & CTRL_FRC_PS_MASK) >> CTRL_FRC_PS_SHIFT) + 1;*/
+        ptimer_set_freq(s->frc_timer, freq);
+        ptimer_set_limit(s->frc_timer,
+            ((s->control & CTRL_FRC_PS_MASK) >> CTRL_FRC_PS_SHIFT) + 1,
+            s->control & CTRL_FRC_EN);
+
+        freq = APBCLOCK_FREQ;
+        freq /= s->prediv + 1;
+        switch ((s->control & CTRL_PS_MASK) >> CTRL_PS_SHIFT) {
+        case 1:
+            freq >>= 4;
+            break;
+        case 2:
+            freq >>= 8;
+            break;
+        default:
+            break;
+        }
+        ptimer_set_freq(s->timer, freq);
+        ptimer_set_limit(s->timer, s->load, s->control & CTRL_TIMER_EN);
+
+        if (s->control & CTRL_TIMER_EN) {
+            ptimer_run(s->timer, 0);
+        }
+        if (s->control & CTRL_FRC_EN) {
+            s->frc_value++;
+            ptimer_run(s->frc_timer, 0);
+        }
+        break;
+    case 0xc:
+        s->raw_irq = 0;
+        qemu_set_irq(s->irq, 0);
+        break;
+    case 0x10:
+    case 0x14:
+        break;
+    case 0x18:
+        s->load = value;
+        ptimer_set_limit(s->timer, s->load, 0);
+        break;
+    case 0x1c:
+        s->prediv = value & 0x3ff;
+        break;
+    case 0x20:
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_timer_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+}
+
+static const MemoryRegionOps bcm2835_timer_ops = {
+    .read = bcm2835_timer_read,
+    .write = bcm2835_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_bcm2835_timer = {
+    .name = "bcm2835_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_timer_init(SysBusDevice *sbd)
+{
+    QEMUBH *bh;
+
+    /* bcm2835_timer_state *s = FROM_SYSBUS(bcm2835_timer_state, dev); */
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_timer_state *s = BCM2835_TIMER(dev);
+
+    s->load = 0;
+    s->control = 0x3e << 16;
+    s->raw_irq = 0;
+    s->prediv = 0x7d;
+
+    bh = qemu_bh_new(timer_tick, s);
+    s->timer = ptimer_init(bh);
+
+    bh = qemu_bh_new(frc_timer_tick, s);
+    s->frc_timer = ptimer_init(bh);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_timer_ops, s,
+        "bcm2835_timer", 0x100);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_timer, s);
+
+    sysbus_init_irq(sbd, &s->irq);
+
+    return 0;
+}
+
+static void bcm2835_timer_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = bcm2835_timer_init;
+}
+
+static TypeInfo bcm2835_timer_info = {
+    .name          = "bcm2835_timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_timer_state),
+    .class_init    = bcm2835_timer_class_init,
+};
+
+static void bcm2835_timer_register_types(void)
+{
+    type_register_static(&bcm2835_timer_info);
+}
+
+type_init(bcm2835_timer_register_types)
diff --git a/hw/arm/bcm2835_todo.c b/hw/arm/bcm2835_todo.c
new file mode 100644
index 0000000..aa7d556
--- /dev/null
+++ b/hw/arm/bcm2835_todo.c
@@ -0,0 +1,93 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+
+/* #define LOG_REG_ACCESS */
+
+#define TYPE_BCM2835_TODO "bcm2835_todo"
+#define BCM2835_TODO(obj) \
+        OBJECT_CHECK(bcm2835_todo_state, (obj), TYPE_BCM2835_TODO)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+} bcm2835_todo_state;
+
+static uint64_t bcm2835_todo_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835: unmapped read(%x)\n", (int)offset);
+#endif
+    /* "Unlocks" RiscOS boot */
+    if (offset == 0x980010) {
+        return 0xffffffff;
+    }
+
+    return 0;
+}
+
+static void bcm2835_todo_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+#ifdef LOG_REG_ACCESS
+    printf("[QEMU] bcm2835: unmapped write(%x) %llx\n", (int)offset, value);
+#endif
+}
+
+static const MemoryRegionOps bcm2835_todo_ops = {
+    .read = bcm2835_todo_read,
+    .write = bcm2835_todo_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_bcm2835_todo = {
+    .name = "bcm2835_todo",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_todo_init(SysBusDevice *sbd)
+{
+    /* bcm2835_todo_state *s = FROM_SYSBUS(bcm2835_todo_state, dev); */
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_todo_state *s = BCM2835_TODO(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_todo_ops, s,
+        "bcm2835_todo", 0x1000000);
+    sysbus_init_mmio(sbd, &s->iomem);
+
+    vmstate_register(dev, -1, &vmstate_bcm2835_todo, s);
+
+    return 0;
+}
+
+static void bcm2835_todo_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = bcm2835_todo_init;
+}
+
+static TypeInfo bcm2835_todo_info = {
+    .name          = "bcm2835_todo",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_todo_state),
+    .class_init    = bcm2835_todo_class_init,
+};
+
+static void bcm2835_todo_register_types(void)
+{
+    type_register_static(&bcm2835_todo_info);
+}
+
+type_init(bcm2835_todo_register_types)
diff --git a/hw/arm/bcm2835_usb.c b/hw/arm/bcm2835_usb.c
new file mode 100644
index 0000000..44a8461
--- /dev/null
+++ b/hw/arm/bcm2835_usb.c
@@ -0,0 +1,777 @@
+/*
+ * Raspberry Pi emulation (c) 2012-2013 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+/* This is wrong at so many levels, but well, I'm releasing it anyway */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "hw/qdev.h"
+#include "sysemu/dma.h"
+#include "hw/usb.h"
+
+#include "bcm2835_usb_regs.h"
+
+#define LOG_REG_LEVEL 2
+
+/* You may have to change these parameters to get an almost-usable mouse
+ * support.
+ * The problem is that frame scheduling is all done by software, so a LOT of
+ * interrupts are generated, which doesn't help... */
+#define SOF_INCR 1
+#define SOF_DELAY 5000
+
+#define NB_HCHANS 8
+
+
+#define TYPE_BCM2835_USB "bcm2835_usb"
+#define BCM2835_USB(obj) \
+        OBJECT_CHECK(bcm2835_usb_state, (obj), TYPE_BCM2835_USB)
+
+typedef struct bcm2835_usb_state_struct bcm2835_usb_state;
+
+typedef struct {
+    bcm2835_usb_state *parent;
+    int index;
+
+    uint32_t hcchar;
+    uint32_t hcsplt;
+    uint32_t hcint;
+    uint32_t hcintmsk;
+    uint32_t hctsiz;
+    uint32_t hcdma;
+    uint32_t reserved;
+    uint32_t hcdmab;
+
+    USBPacket packet;
+    uint8_t buffer[8192];
+} bcm2835_usb_hc_state;
+
+struct bcm2835_usb_state_struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    /* DMAContext *dma; */
+    AddressSpace *dma;
+
+    USBBus bus;
+    USBPort port;
+    int attached;
+    int reset_done;
+    QEMUTimer *sof_timer;
+
+
+    uint32_t gusbcfg;
+    uint32_t hptxfsiz;
+    uint32_t hcfg;
+    uint32_t dcfg;
+    uint32_t grxfsiz;
+    uint32_t gnptxfsiz;
+    uint32_t dtxfsiz[15];
+    uint32_t gahbcfg;
+    uint32_t grstctl;
+    uint32_t gotgctl;
+    uint32_t gotgint;
+    uint32_t gintsts;
+    uint32_t gintmsk;
+    uint32_t gdfifocfg;
+    uint32_t hprt0;
+    uint32_t haint;
+    uint32_t haintmsk;
+    uint32_t gnptxsts;
+    uint32_t hfnum;
+    uint32_t hptxsts;
+
+    bcm2835_usb_hc_state hchan[NB_HCHANS];
+
+    qemu_irq irq;
+
+};
+
+static void bcm2835_usb_update_irq(bcm2835_usb_state *s)
+{
+    int n;
+
+    s->haint = 0;
+    for (n = 0; n < NB_HCHANS; n++) {
+        if (s->hchan[n].hcint & s->hchan[n].hcintmsk) {
+            s->haint |= (1 << n);
+        }
+    }
+    s->gintsts &= ~gintsts_hcintr;
+    if (s->haint & s->haintmsk) {
+        s->gintsts |= gintsts_hcintr;
+    }
+
+    if ((s->hprt0 & hprt0_prtconndet)
+        || (s->hprt0 & hprt0_prtenchng)
+   ) {
+        s->gintsts |= gintsts_portintr;
+    } else {
+        s->gintsts &= ~gintsts_portintr;
+    }
+
+    s->gintsts |= gintsts_nptxfempty | gintsts_ptxfempty;
+
+    if (!(s->gahbcfg & gahbcfg_glblintrmsk)) {
+        qemu_set_irq(s->irq, 0);
+    } else {
+        /*printf("[QEMU] bcm2835_usb_update_irq gintsts=%08x gintmsk=%08x\n",
+            s->gintsts, s->gintmsk);*/
+        if (s->gintsts & s->gintmsk) {
+            qemu_set_irq(s->irq, 1);
+        } else {
+            qemu_set_irq(s->irq, 0);
+        }
+    }
+}
+
+
+static void bcm2835_usb_sof_tick(void *opaque)
+{
+    bcm2835_usb_state *s = (bcm2835_usb_state *)opaque;
+    int64_t now;
+
+    uint32_t num = (s->hfnum & 0x3fff) + SOF_INCR;
+    s->hfnum = (num & 0x3fff) | (0x3210 << 16);
+    s->gintsts |= gintsts_sofintr;
+
+    bcm2835_usb_update_irq(s);
+
+    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / SCALE_US;
+    timer_mod(s->sof_timer, now + SOF_DELAY);
+}
+
+static void channel_enable(bcm2835_usb_hc_state *c)
+{
+    /* int n; */
+    USBEndpoint *ep;
+    USBDevice *dev;
+
+    uint32_t epnum = (c->hcchar >> hcchar_epnum_shift) & hcchar_epnum_mask;
+    uint32_t devaddr = (c->hcchar >> hcchar_devaddr_shift)
+                       & hcchar_devaddr_mask;
+    uint32_t xfersize = (c->hctsiz >> hctsiz_xfersize_shift)
+                        & hctsiz_xfersize_mask;
+    /* uint32_t pktcnt = (c->hctsiz >> hctsiz_pktcnt_shift)
+                      & hctsiz_pktcnt_mask; */
+    uint32_t pid = (c->hctsiz >> hctsiz_pid_shift) & hctsiz_pid_mask;
+    uint32_t dma_addr = c->hcdma; /* ??? */
+    /* uint32_t dma_addr_b = c->hcdmab; / * ??? */
+    int actual_length;
+    int qpid;
+
+    if (!c->parent->reset_done) {
+        return;
+    }
+
+    /*printf("DEV = %d EPNUM = %d EPDIR = %s PKTCNT = %d XFERSIZE = %d\n",
+        devaddr, epnum, (c->hcchar & hcchar_epdir ? "IN" : "OUT"),
+        pktcnt, xfersize);*/
+
+    if (c->hcchar & hcchar_epdir) {
+        /* IN */
+        qpid = USB_TOKEN_IN;
+    } else {
+        /* OUT/SETUP */
+        if (pid == DWC_HCTSIZ_SETUP) {
+            qpid = USB_TOKEN_SETUP;
+        } else {
+            qpid = USB_TOKEN_OUT;
+        }
+    }
+    /* printf("QPID = %02x\n", qpid); */
+    dev = usb_find_device(&c->parent->port, devaddr);
+
+    assert(dev != NULL);
+
+    ep = usb_ep_get(dev, qpid, epnum);
+    usb_packet_setup(&c->packet, qpid, ep, 0, devaddr, 0, 0);
+
+    if (xfersize > 0) {
+        dma_memory_read(c->parent->dma, dma_addr, c->buffer, xfersize);
+
+        /*for (n = 0; n < xfersize; n++) {
+            printf("%02x", c->buffer[n]);
+        }
+        printf("\n\n");*/
+
+        usb_packet_addbuf(&c->packet, c->buffer, xfersize);
+    }
+    usb_handle_packet(dev, &c->packet);
+    /*printf("PACKET STATUS = %d actual_length=%d\n",
+        c->packet.status, c->packet.actual_length);*/
+
+    if (c->packet.status == USB_RET_SUCCESS) {
+        if (qpid == USB_TOKEN_IN) {
+            actual_length = c->packet.actual_length;
+
+            xfersize -= actual_length;
+            c->hctsiz &= ~(hctsiz_xfersize_mask << hctsiz_xfersize_shift);
+            c->hctsiz |= xfersize << hctsiz_xfersize_shift;
+
+            dma_memory_write(c->parent->dma, dma_addr, c->buffer,
+                actual_length);
+
+            /*for (n = 0; n < actual_length; n++) {
+                printf("%02x", c->buffer[n]);
+            }
+            printf("\n\n");*/
+        }
+
+        c->hcint |= hcint_xfercomp | hcint_chhltd;
+        bcm2835_usb_update_irq(c->parent);
+    } else if (c->packet.status == USB_RET_NAK) {
+        c->hcint |= hcint_chhltd | hcint_nak;
+        bcm2835_usb_update_irq(c->parent);
+    } else {
+        assert(0);
+    }
+
+}
+
+static uint32_t bcm2835_usb_hchan_read(bcm2835_usb_state *s, int ch,
+    int offset)
+{
+
+    bcm2835_usb_hc_state *c = &s->hchan[ch];
+    uint32_t res;
+    int log = 0;
+    const char *reg = "(unmapped)";
+
+    switch (offset) {
+    case 0x0:
+        reg = "hcchar";
+        res = c->hcchar;
+        break;
+    case 0x4:
+        reg = "hcsplt";
+        res = c->hcsplt;
+        break;
+    case 0x8:
+        reg = "hcint";
+        res = c->hcint;
+        break;
+    case 0xc:
+        reg = "hcintmsk";
+        res = c->hcintmsk;
+        break;
+    case 0x10:
+        reg = "hctsiz";
+        res = c->hctsiz;
+        break;
+    case 0x14:
+        reg = "hcdma";
+        res = c->hcdma;
+        break;
+    case 0x1c:
+        reg = "hcdmab";
+        res = c->hcdmab;
+        break;
+    default:
+        res = 0;
+        break;
+    }
+
+    if (log > LOG_REG_LEVEL) {
+        printf("[QEMU] bcm2835_usb: read_hc[%d](%x) %08x <%s>\n", ch,
+            (int)offset, res, reg);
+    }
+
+    return res;
+}
+static void bcm2835_usb_hchan_write(bcm2835_usb_state *s, int ch,
+    int offset, uint32_t value, int *pset_irq)
+{
+    int log = 0;
+    bcm2835_usb_hc_state *c = &s->hchan[ch];
+
+    const char *reg = "(unmapped)";
+
+    switch (offset) {
+    case 0x0:
+        reg = "hcchar";
+        c->hcchar = value;
+        if (value & hcchar_chdis) {
+            c->hcchar &= ~(hcchar_chdis | hcchar_chen);
+            /* TODO irq */
+        }
+        if (value & hcchar_chen) {
+            channel_enable(c);
+        }
+        break;
+    case 0x4:
+        reg = "hcsplt";
+        c->hcsplt = value;
+        break;
+    case 0x8:
+        /* Looks like a standard interrupt register */
+        reg = "hcint";
+        c->hcint &= ~value;
+        *pset_irq = 1;
+        break;
+    case 0xc:
+        reg = "hcintmsk";
+        c->hcintmsk = value;
+        break;
+    case 0x10:
+        reg = "hctsiz";
+        c->hctsiz = value;
+        break;
+    case 0x14:
+        reg = "hcdma";
+        c->hcdma = value;
+        break;
+    case 0x1c:
+        reg = "hcdmab";
+        c->hcdmab = value;
+        break;
+    default:
+        break;
+    }
+
+    if (log > LOG_REG_LEVEL) {
+        printf("[QEMU] bcm2835_usb: write_hc[%d](%x) %08x >%s<\n", ch,
+            (int)offset, value, reg);
+    }
+
+}
+
+static uint64_t bcm2835_usb_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_usb_state *s = (bcm2835_usb_state *)opaque;
+    uint32_t res = 0;
+
+    const char *reg = "(unmapped)";
+    int log = 1;
+
+    int i;
+
+    assert(size == 4);
+
+    switch (offset) {
+    case 0x0:
+        reg = "gotgctl";
+        res = s->gotgctl;
+        break;
+    case 0x4:
+        reg = "gotgint";
+        res = s->gotgint;
+        break;
+    case 0x8:
+        reg = "gahbcfg";
+        res = s->gahbcfg;
+        break;
+    case 0xc:
+        reg = "gusbcfg";
+        res = s->gusbcfg;
+        break;
+    case 0x10:
+        reg = "grstctl";
+        res = s->grstctl;
+        break;
+    case 0x14:
+        reg = "gintsts";
+        res = s->gintsts;
+        /* Enforce Host mode */
+        res |= gintsts_curmode;
+        break;
+    case 0x18:
+        reg = "gintmsk";
+        res = s->gintmsk;
+        break;
+    case 0x24:
+        reg = "grxfsiz";
+        res = s->grxfsiz;
+        break;
+    case 0x28:
+        reg = "gnptxfsiz";
+        res = s->gnptxfsiz;
+        break;
+    case 0x2c:
+        reg = "gnptxsts";
+        res = s->gnptxsts;
+        break;
+    case 0x40:
+        reg = "gsnpsid";
+        res = 0x4f54280a;
+        break;
+    case 0x44:
+        reg = "ghwcfg1";
+        res = 0;
+        break;
+    case 0x48:
+        reg = "ghwcfg2";
+        res = 0x228ddd50;
+        break;
+    case 0x4c:
+        reg = "ghwcfg3";
+        res = 0x0ff000e8;
+        break;
+    case 0x50:
+        reg = "ghwcfg4";
+        res = 0x1ff00020;
+        break;
+    case 0x5c:
+        reg = "gdfifocfg";
+        res = s->gdfifocfg;
+        break;
+    case 0x100:
+        reg = "hptxfsiz";
+        res = s->hptxfsiz;
+        break;
+    case 0x400:
+        reg = "hcfg";
+        res = s->hcfg;
+        break;
+    case 0x408:
+        reg = "hfnum";
+        res = s->hfnum;
+        break;
+    case 0x410:
+        reg = "hptxsts";
+        res = s->hptxsts;
+        break;
+    case 0x414:
+        reg = "haint";
+        res = s->haint;
+        break;
+    case 0x418:
+        reg = "haintmsk";
+        res = s->haintmsk;
+        break;
+    case 0x440:
+        reg = "hprt0";
+        res = s->hprt0;
+        res &= ~hprt0_prtconnsts;
+        if (s->attached) {
+            res |= hprt0_prtconnsts;
+        }
+        break;
+    case 0x800:
+        reg = "dcfg";
+        res = s->dcfg;
+        break;
+
+    case 0xe00:
+    case 0x54:
+    case 0x58:
+        reg = "(power-related)";
+        res = 0;
+        break;
+
+    default:
+        if ((offset >= 0x104) && (offset < 0x104 + (15 << 2))) {
+            reg = "dtxfsiz[0..14]";
+            res = s->dtxfsiz[(offset - 0x104) >> 2];
+        } else if ((offset >= 0x500) && (offset < 0x500 + 0x20*NB_HCHANS)) {
+            i = (offset - 0x500) >> 5;
+            res = bcm2835_usb_hchan_read(s, i, offset & 0x1f);
+            log = 0;
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                "bcm2835_usb_read: Bad offset %x\n", (int)offset);
+            res = 0;
+        }
+        break;
+    }
+
+    if (log > LOG_REG_LEVEL) {
+        printf("[QEMU] bcm2835_usb: read(%x) %08x <%s>\n", (int)offset,
+            res, reg);
+    }
+
+    return res;
+}
+
+static void bcm2835_usb_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+    bcm2835_usb_state *s = (bcm2835_usb_state *)opaque;
+
+    const char *reg = "(unmapped)";
+    int log = 1;
+
+    int i;
+    int set_irq = 0;
+
+    assert(size == 4);
+
+    switch (offset) {
+    case 0x0:
+        reg = "gotgctl";
+        s->gotgctl = value;
+        break;
+    case 0x4:
+        /* Looks like a standard interrupt register */
+        reg = "gotgint";
+        s->gotgint &= ~value;
+        break;
+    case 0x8:
+        reg = "gahbcfg";
+        s->gahbcfg = value;
+        set_irq = 1;
+        break;
+    case 0xc:
+        reg = "gusbcfg";
+        s->gusbcfg = value;
+        break;
+    case 0x10:
+        reg = "grstctl";
+        s->grstctl &= ~0x7c0;
+        s->grstctl |= value & 0x7c0;
+        break;
+    case 0x14:
+        reg = "gintsts";
+        /*if (value & gintsts_sofintr)
+            s->gintsts &= ~gintsts_sofintr;*/
+        s->gintsts &= ~value;
+        /* Enforce Host mode */
+        s->gintsts |= gintsts_curmode;
+        set_irq = 1;
+        break;
+    case 0x18:
+        reg = "gintmsk";
+        s->gintmsk = value;
+        break;
+    case 0x24:
+        reg = "grxfsiz";
+        s->grxfsiz = value;
+        break;
+    case 0x28:
+        reg = "gnptxfsiz";
+        s->gnptxfsiz = value;
+        break;
+    case 0x5c:
+        reg = "gdfifocfg";
+        s->gdfifocfg = value;
+        break;
+    case 0x100:
+        reg = "hptxfsiz";
+        s->hptxfsiz = value;
+        break;
+    case 0x400:
+        reg = "hcfg";
+        s->hcfg = value;
+        break;
+    case 0x408:
+        reg = "hfnum";
+        /* Probably RO */
+        break;
+    case 0x410:
+        reg = "hptxsts";
+        /* Probably RO */
+        break;
+    case 0x414:
+        reg = "haint";
+        /* Probably RO */
+        break;
+    case 0x418:
+        reg = "haintmsk";
+        s->haintmsk = value & ((1 << NB_HCHANS) - 1);
+        set_irq = 1;
+        break;
+    case 0x440:
+        reg = "hprt0";
+        if (!(s->hprt0 & hprt0_prtpwr) && (value & hprt0_prtpwr)) {
+            /* Trigger the port status change interrupt on power on */
+            if (s->attached) {
+                s->hprt0 |= hprt0_prtconndet;
+                set_irq = 1;
+                /* Reset the device (that's probably not the right place) */
+                usb_device_reset(s->port.dev);
+                s->reset_done = 1;
+                timer_mod(s->sof_timer, 0);
+            }
+        }
+        s->hprt0 &= ~hprt0_prtpwr;
+        s->hprt0 |= value & hprt0_prtpwr;
+
+        if ((s->hprt0 & hprt0_prtres) ^ (value & hprt0_prtres)) {
+            s->hprt0 |= hprt0_prtenchng;
+            set_irq = 1;
+        }
+        s->hprt0 &= ~(hprt0_prtena | hprt0_prtres);
+        if (value & hprt0_prtres) {
+            s->hprt0 |= hprt0_prtres;
+        } else {
+            s->hprt0 |= hprt0_prtena;
+        }
+
+        /* Interrupt clears */
+        if (value & hprt0_prtconndet) {
+            s->hprt0 &= ~hprt0_prtconndet;
+            set_irq = 1;
+        }
+        if (value & hprt0_prtenchng) {
+            s->hprt0 &= ~hprt0_prtenchng;
+            set_irq = 1;
+        }
+
+        break;
+
+    case 0xe00:
+    case 0x54:
+    case 0x58:
+        reg = "(power-related)";
+        break;
+
+    default:
+        if ((offset >= 0x104) && (offset < 0x104 + (15 << 2))) {
+            reg = "dtxfsiz[0..14]";
+            s->dtxfsiz[(offset - 0x104) >> 2] = value;
+        } else if ((offset >= 0x500) && (offset < 0x500 + 0x20*NB_HCHANS)) {
+            i = (offset - 0x500) >> 5;
+            bcm2835_usb_hchan_write(s, i, offset & 0x1f, value, &set_irq);
+            log = 0;
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                "bcm2835_usb_write: Bad offset %x\n", (int)offset);
+        }
+        break;
+    }
+
+    if (log > LOG_REG_LEVEL) {
+        printf("[QEMU] bcm2835_usb: write(%x) %08x >%s<\n", (int)offset,
+            (uint32_t)value, reg);
+    }
+    if (set_irq) {
+        bcm2835_usb_update_irq(s);
+    }
+}
+
+static void bcm2835_usb_attach(USBPort *port1)
+{
+    bcm2835_usb_state *s = port1->opaque;
+    s->attached = 1;
+}
+static void bcm2835_usb_detach(USBPort *port1)
+{
+}
+static void bcm2835_usb_child_detach(USBPort *port1, USBDevice *child)
+{
+}
+static void bcm2835_usb_wakeup(USBPort *port1)
+{
+}
+static void bcm2835_usb_async_complete(USBPort *port, USBPacket *packet)
+{
+    printf("******************* ASYNC COMPLETE\n");
+}
+
+
+static const MemoryRegionOps bcm2835_usb_ops = {
+    .read = bcm2835_usb_read,
+    .write = bcm2835_usb_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_bcm2835_usb = {
+    .name = "bcm2835_usb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static USBPortOps bcm2835_usb_port_ops = {
+    .attach = bcm2835_usb_attach,
+    .detach = bcm2835_usb_detach,
+    .child_detach = bcm2835_usb_child_detach,
+    .wakeup = bcm2835_usb_wakeup,
+    .complete = bcm2835_usb_async_complete,
+};
+
+static USBBusOps bcm2835_usb_bus_ops = {
+};
+
+static int bcm2835_usb_init(SysBusDevice *sbd)
+{
+    /* bcm2835_usb_state *s = FROM_SYSBUS(bcm2835_usb_state, dev); */
+    int n;
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_usb_state *s = BCM2835_USB(dev);
+
+    /* s->dma = &dma_context_memory; */
+    s->dma = &address_space_memory;
+
+    s->gusbcfg = 0x20402700;
+    s->hptxfsiz = 0x02002000;
+    s->hcfg = 0x00000001;
+    s->dcfg = 0x00000000;
+    s->grxfsiz = 0x00001000;
+    s->gnptxfsiz = 0x01001000;
+    for (n = 0; n < 15; n++) {
+        s->dtxfsiz[n] = 0x02002000;
+    }
+    s->gahbcfg = 0x0000000e;
+    s->grstctl = 0x80000000;
+    s->gotgctl = 0x001c0000;
+    s->gotgint = 0;
+    s->gintsts = 0;
+    s->gintmsk = 0;
+    s->gdfifocfg = 0x00000000;
+    /* s->hprt0 = 0x00000400; */
+    s->hprt0 = DWC_HPRT0_PRTSPD_FULL_SPEED << hprt0_prtspd_shift;
+    s->gnptxsts = 0x080100;
+    s->hfnum = 0;
+    s->hptxsts = 0x080200;
+
+    for (n = 0; n < NB_HCHANS; n++) {
+        s->hchan[n].parent = s;
+        s->hchan[n].index = n;
+
+        s->hchan[n].hcchar = 0;
+        s->hchan[n].hcsplt = 0;
+        s->hchan[n].hcint = 0;
+        s->hchan[n].hcintmsk = 0;
+        s->hchan[n].hctsiz = 0;
+        s->hchan[n].hcdma = 0;
+        s->hchan[n].hcdmab = 0;
+
+        usb_packet_init(&s->hchan[n].packet);
+    }
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_usb_ops, s,
+        "bcm2835_usb", 0x20000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_usb, s);
+
+    sysbus_init_irq(sbd, &s->irq);
+
+    s->attached = 0;
+    s->reset_done = 0;
+
+    s->sof_timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_US,
+                       bcm2835_usb_sof_tick, s);
+
+    usb_bus_new(&s->bus, sizeof(s->bus), &bcm2835_usb_bus_ops, dev);
+    usb_register_port(&s->bus, &s->port, s, 0, &bcm2835_usb_port_ops,
+        USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+    return 0;
+}
+
+static void bcm2835_usb_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = bcm2835_usb_init;
+}
+
+static TypeInfo bcm2835_usb_info = {
+    .name          = "bcm2835_usb",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_usb_state),
+    .class_init    = bcm2835_usb_class_init,
+};
+
+static void bcm2835_usb_register_types(void)
+{
+    type_register_static(&bcm2835_usb_info);
+}
+
+type_init(bcm2835_usb_register_types)
diff --git a/hw/arm/bcm2835_usb_regs.h b/hw/arm/bcm2835_usb_regs.h
new file mode 100644
index 0000000..76f3219
--- /dev/null
+++ b/hw/arm/bcm2835_usb_regs.h
@@ -0,0 +1,1061 @@
+#ifndef BCM2835_USB_REGS_H
+#define BCM2835_USB_REGS_H
+
+#define __DWC_OTG_REGS_H__
+#define DWC_GLBINTRMASK        0x0001
+#define DWC_DMAENABLE        0x0020
+#define DWC_NPTXEMPTYLVL_EMPTY    0x0080
+#define DWC_NPTXEMPTYLVL_HALFEMPTY    0x0000
+#define DWC_PTXEMPTYLVL_EMPTY    0x0100
+#define DWC_PTXEMPTYLVL_HALFEMPTY    0x0000
+#define DWC_SLAVE_ONLY_ARCH 0
+#define DWC_EXT_DMA_ARCH 1
+#define DWC_INT_DMA_ARCH 2
+#define DWC_MODE_HNP_SRP_CAPABLE    0
+#define DWC_MODE_SRP_ONLY_CAPABLE    1
+#define DWC_MODE_NO_HNP_SRP_CAPABLE        2
+#define DWC_MODE_SRP_CAPABLE_DEVICE        3
+#define DWC_MODE_NO_SRP_CAPABLE_DEVICE    4
+#define DWC_MODE_SRP_CAPABLE_HOST    5
+#define DWC_MODE_NO_SRP_CAPABLE_HOST    6
+
+/* union gotgctl_data */
+#define gotgctl_sesreqscs (1 << 0)
+#define gotgctl_sesreq (1 << 1)
+#define gotgctl_vbvalidoven (1 << 2)
+#define gotgctl_vbvalidovval (1 << 3)
+#define gotgctl_avalidoven (1 << 4)
+#define gotgctl_avalidovval (1 << 5)
+#define gotgctl_bvalidoven (1 << 6)
+#define gotgctl_bvalidovval (1 << 7)
+#define gotgctl_hstnegscs (1 << 8)
+#define gotgctl_hnpreq (1 << 9)
+#define gotgctl_hstsethnpen (1 << 10)
+#define gotgctl_devhnpen (1 << 11)
+#define gotgctl_reserved12_15_shift (12)
+#define gotgctl_reserved12_15_mask (0xf)
+#define gotgctl_conidsts (1 << 16)
+#define gotgctl_dbnctime (1 << 17)
+#define gotgctl_asesvld (1 << 18)
+#define gotgctl_bsesvld (1 << 19)
+#define gotgctl_otgver (1 << 20)
+#define gotgctl_reserved1 (1 << 21)
+#define gotgctl_multvalidbc_shift (22)
+#define gotgctl_multvalidbc_mask (0x1f)
+#define gotgctl_chirpen (1 << 27)
+#define gotgctl_reserved28_31_shift (28)
+#define gotgctl_reserved28_31_mask (0xf)
+
+/* union gotgint_data */
+#define gotgint_reserved0_1_shift (0)
+#define gotgint_reserved0_1_mask (0x3)
+#define gotgint_sesenddet (1 << 2)
+#define gotgint_reserved3_7_shift (3)
+#define gotgint_reserved3_7_mask (0x1f)
+#define gotgint_sesreqsucstschng (1 << 8)
+#define gotgint_hstnegsucstschng (1 << 9)
+#define gotgint_reserved10_16_shift (10)
+#define gotgint_reserved10_16_mask (0x7f)
+#define gotgint_hstnegdet (1 << 17)
+#define gotgint_adevtoutchng (1 << 18)
+#define gotgint_debdone (1 << 19)
+#define gotgint_mvic (1 << 20)
+#define gotgint_reserved31_21_shift (21)
+#define gotgint_reserved31_21_mask (0x7ff)
+
+/* union gahbcfg_data */
+#define gahbcfg_glblintrmsk (1 << 0)
+#define DWC_GAHBCFG_GLBINT_ENABLE        1
+#define gahbcfg_hburstlen_shift (1)
+#define gahbcfg_hburstlen_mask (0xf)
+#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE    0
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR        1
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR4        3
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR8        5
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR16    7
+#define gahbcfg_dmaenable (1 << 5)
+#define DWC_GAHBCFG_DMAENABLE            1
+#define gahbcfg_reserved (1 << 6)
+#define gahbcfg_nptxfemplvl_txfemplvl (1 << 7)
+#define gahbcfg_ptxfemplvl (1 << 8)
+#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY        1
+#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY    0
+#define gahbcfg_reserved9_20_shift (9)
+#define gahbcfg_reserved9_20_mask (0xfff)
+#define gahbcfg_remmemsupp (1 << 21)
+#define gahbcfg_notialldmawrit (1 << 22)
+#define gahbcfg_ahbsingle (1 << 23)
+#define gahbcfg_reserved24_31_shift (24)
+#define gahbcfg_reserved24_31_mask (0xff)
+
+/* union gusbcfg_data */
+#define gusbcfg_toutcal_shift (0)
+#define gusbcfg_toutcal_mask (0x7)
+#define gusbcfg_phyif (1 << 3)
+#define gusbcfg_ulpi_utmi_sel (1 << 4)
+#define gusbcfg_fsintf (1 << 5)
+#define gusbcfg_physel (1 << 6)
+#define gusbcfg_ddrsel (1 << 7)
+#define gusbcfg_srpcap (1 << 8)
+#define gusbcfg_hnpcap (1 << 9)
+#define gusbcfg_usbtrdtim_shift (10)
+#define gusbcfg_usbtrdtim_mask (0xf)
+#define gusbcfg_reserved1 (1 << 14)
+#define gusbcfg_phylpwrclksel (1 << 15)
+#define gusbcfg_otgutmifssel (1 << 16)
+#define gusbcfg_ulpi_fsls (1 << 17)
+#define gusbcfg_ulpi_auto_res (1 << 18)
+#define gusbcfg_ulpi_clk_sus_m (1 << 19)
+#define gusbcfg_ulpi_ext_vbus_drv (1 << 20)
+#define gusbcfg_ulpi_int_vbus_indicator (1 << 21)
+#define gusbcfg_term_sel_dl_pulse (1 << 22)
+#define gusbcfg_indicator_complement (1 << 23)
+#define gusbcfg_indicator_pass_through (1 << 24)
+#define gusbcfg_ulpi_int_prot_dis (1 << 25)
+#define gusbcfg_ic_usb_cap (1 << 26)
+#define gusbcfg_ic_traffic_pull_remove (1 << 27)
+#define gusbcfg_tx_end_delay (1 << 28)
+#define gusbcfg_force_host_mode (1 << 29)
+#define gusbcfg_force_dev_mode (1 << 30)
+#define gusbcfg_reserved31 (1 << 31)
+
+/* union grstctl_data */
+#define grstctl_csftrst (1 << 0)
+#define grstctl_hsftrst (1 << 1)
+#define grstctl_hstfrm (1 << 2)
+#define grstctl_intknqflsh (1 << 3)
+#define grstctl_rxfflsh (1 << 4)
+#define grstctl_txfflsh (1 << 5)
+#define grstctl_txfnum_shift (6)
+#define grstctl_txfnum_mask (0x1f)
+#define grstctl_reserved11_29_shift (11)
+#define grstctl_reserved11_29_mask (0x7ffff)
+#define grstctl_dmareq (1 << 30)
+#define grstctl_ahbidle (1 << 31)
+
+/* union gintmsk_data */
+#define gintmsk_reserved0 (1 << 0)
+#define gintmsk_modemismatch (1 << 1)
+#define gintmsk_otgintr (1 << 2)
+#define gintmsk_sofintr (1 << 3)
+#define gintmsk_rxstsqlvl (1 << 4)
+#define gintmsk_nptxfempty (1 << 5)
+#define gintmsk_ginnakeff (1 << 6)
+#define gintmsk_goutnakeff (1 << 7)
+#define gintmsk_ulpickint (1 << 8)
+#define gintmsk_i2cintr (1 << 9)
+#define gintmsk_erlysuspend (1 << 10)
+#define gintmsk_usbsuspend (1 << 11)
+#define gintmsk_usbreset (1 << 12)
+#define gintmsk_enumdone (1 << 13)
+#define gintmsk_isooutdrop (1 << 14)
+#define gintmsk_eopframe (1 << 15)
+#define gintmsk_restoredone (1 << 16)
+#define gintmsk_epmismatch (1 << 17)
+#define gintmsk_inepintr (1 << 18)
+#define gintmsk_outepintr (1 << 19)
+#define gintmsk_incomplisoin (1 << 20)
+#define gintmsk_incomplisoout (1 << 21)
+#define gintmsk_fetsusp (1 << 22)
+#define gintmsk_resetdet (1 << 23)
+#define gintmsk_portintr (1 << 24)
+#define gintmsk_hcintr (1 << 25)
+#define gintmsk_ptxfempty (1 << 26)
+#define gintmsk_lpmtranrcvd (1 << 27)
+#define gintmsk_conidstschng (1 << 28)
+#define gintmsk_disconnect (1 << 29)
+#define gintmsk_sessreqintr (1 << 30)
+#define gintmsk_wkupintr (1 << 31)
+
+/* union gintsts_data */
+#define DWC_SOF_INTR_MASK 0x0008
+#define DWC_HOST_MODE 1
+#define gintsts_curmode (1 << 0)
+#define gintsts_modemismatch (1 << 1)
+#define gintsts_otgintr (1 << 2)
+#define gintsts_sofintr (1 << 3)
+#define gintsts_rxstsqlvl (1 << 4)
+#define gintsts_nptxfempty (1 << 5)
+#define gintsts_ginnakeff (1 << 6)
+#define gintsts_goutnakeff (1 << 7)
+#define gintsts_ulpickint (1 << 8)
+#define gintsts_i2cintr (1 << 9)
+#define gintsts_erlysuspend (1 << 10)
+#define gintsts_usbsuspend (1 << 11)
+#define gintsts_usbreset (1 << 12)
+#define gintsts_enumdone (1 << 13)
+#define gintsts_isooutdrop (1 << 14)
+#define gintsts_eopframe (1 << 15)
+#define gintsts_restoredone (1 << 16)
+#define gintsts_epmismatch (1 << 17)
+#define gintsts_inepint (1 << 18)
+#define gintsts_outepintr (1 << 19)
+#define gintsts_incomplisoin (1 << 20)
+#define gintsts_incomplisoout (1 << 21)
+#define gintsts_fetsusp (1 << 22)
+#define gintsts_resetdet (1 << 23)
+#define gintsts_portintr (1 << 24)
+#define gintsts_hcintr (1 << 25)
+#define gintsts_ptxfempty (1 << 26)
+#define gintsts_lpmtranrcvd (1 << 27)
+#define gintsts_conidstschng (1 << 28)
+#define gintsts_disconnect (1 << 29)
+#define gintsts_sessreqintr (1 << 30)
+#define gintsts_wkupintr (1 << 31)
+
+/* union device_grxsts_data */
+#define device_grxsts_epnum_shift (0)
+#define device_grxsts_epnum_mask (0xf)
+#define device_grxsts_bcnt_shift (4)
+#define device_grxsts_bcnt_mask (0x7ff)
+#define device_grxsts_dpid_shift (15)
+#define device_grxsts_dpid_mask (0x3)
+#define DWC_STS_DATA_UPDT        0x2    /* OUT Data Packet */
+#define DWC_STS_XFER_COMP        0x3    /* OUT Data Transfer Complete */
+#define DWC_DSTS_GOUT_NAK        0x1    /* Global OUT NAK */
+#define DWC_DSTS_SETUP_COMP        0x4    /* Setup Phase Complete */
+#define DWC_DSTS_SETUP_UPDT 0x6    /* SETUP Packet */
+#define device_grxsts_pktsts_shift (17)
+#define device_grxsts_pktsts_mask (0xf)
+#define device_grxsts_fn_shift (21)
+#define device_grxsts_fn_mask (0xf)
+#define device_grxsts_reserved25_31_shift (25)
+#define device_grxsts_reserved25_31_mask (0x7f)
+
+/* union host_grxsts_data */
+#define host_grxsts_chnum_shift (0)
+#define host_grxsts_chnum_mask (0xf)
+#define host_grxsts_bcnt_shift (4)
+#define host_grxsts_bcnt_mask (0x7ff)
+#define host_grxsts_dpid_shift (15)
+#define host_grxsts_dpid_mask (0x3)
+#define host_grxsts_pktsts_shift (17)
+#define host_grxsts_pktsts_mask (0xf)
+#define DWC_GRXSTS_PKTSTS_IN              0x2
+#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP      0x3
+#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
+#define DWC_GRXSTS_PKTSTS_CH_HALTED          0x7
+#define host_grxsts_reserved21_31_shift (21)
+#define host_grxsts_reserved21_31_mask (0x7ff)
+
+/* union fifosize_data */
+#define fifosize_startaddr_shift (0)
+#define fifosize_startaddr_mask (0xffff)
+#define fifosize_depth_shift (16)
+#define fifosize_depth_mask (0xffff)
+
+/* union gnptxsts_data */
+#define gnptxsts_nptxfspcavail_shift (0)
+#define gnptxsts_nptxfspcavail_mask (0xffff)
+#define gnptxsts_nptxqspcavail_shift (16)
+#define gnptxsts_nptxqspcavail_mask (0xff)
+#define gnptxsts_nptxqtop_terminate (1 << 24)
+#define gnptxsts_nptxqtop_token_shift (25)
+#define gnptxsts_nptxqtop_token_mask (0x3)
+#define gnptxsts_nptxqtop_chnep_shift (27)
+#define gnptxsts_nptxqtop_chnep_mask (0xf)
+#define gnptxsts_reserved (1 << 31)
+
+/* union dtxfsts_data */
+#define dtxfsts_txfspcavail_shift (0)
+#define dtxfsts_txfspcavail_mask (0xffff)
+#define dtxfsts_reserved_shift (16)
+#define dtxfsts_reserved_mask (0xffff)
+
+/* union gi2cctl_data */
+#define gi2cctl_rwdata_shift (0)
+#define gi2cctl_rwdata_mask (0xff)
+#define gi2cctl_regaddr_shift (8)
+#define gi2cctl_regaddr_mask (0xff)
+#define gi2cctl_addr_shift (16)
+#define gi2cctl_addr_mask (0x7f)
+#define gi2cctl_i2cen (1 << 23)
+#define gi2cctl_ack (1 << 24)
+#define gi2cctl_i2csuspctl (1 << 25)
+#define gi2cctl_i2cdevaddr_shift (26)
+#define gi2cctl_i2cdevaddr_mask (0x3)
+#define gi2cctl_i2cdatse0 (1 << 28)
+#define gi2cctl_reserved (1 << 29)
+#define gi2cctl_rw (1 << 30)
+#define gi2cctl_bsydne (1 << 31)
+
+/* union gpvndctl_data */
+#define gpvndctl_regdata_shift (0)
+#define gpvndctl_regdata_mask (0xff)
+#define gpvndctl_vctrl_shift (8)
+#define gpvndctl_vctrl_mask (0xff)
+#define gpvndctl_regaddr16_21_shift (16)
+#define gpvndctl_regaddr16_21_mask (0x3f)
+#define gpvndctl_regwr (1 << 22)
+#define gpvndctl_reserved23_24_shift (23)
+#define gpvndctl_reserved23_24_mask (0x3)
+#define gpvndctl_newregreq (1 << 25)
+#define gpvndctl_vstsbsy (1 << 26)
+#define gpvndctl_vstsdone (1 << 27)
+#define gpvndctl_reserved28_30_shift (28)
+#define gpvndctl_reserved28_30_mask (0x7)
+#define gpvndctl_disulpidrvr (1 << 31)
+
+/* union ggpio_data */
+#define ggpio_gpi_shift (0)
+#define ggpio_gpi_mask (0xffff)
+#define ggpio_gpo_shift (16)
+#define ggpio_gpo_mask (0xffff)
+
+/* union guid_data */
+#define guid_rwdata_shift (0)
+#define guid_rwdata_mask (0xffffffff)
+
+/* union gsnpsid_data */
+#define gsnpsid_rwdata_shift (0)
+#define gsnpsid_rwdata_mask (0xffffffff)
+
+/* union hwcfg1_data */
+#define hwcfg1_ep_dir0_shift (0)
+#define hwcfg1_ep_dir0_mask (0x3)
+#define hwcfg1_ep_dir1_shift (2)
+#define hwcfg1_ep_dir1_mask (0x3)
+#define hwcfg1_ep_dir2_shift (4)
+#define hwcfg1_ep_dir2_mask (0x3)
+#define hwcfg1_ep_dir3_shift (6)
+#define hwcfg1_ep_dir3_mask (0x3)
+#define hwcfg1_ep_dir4_shift (8)
+#define hwcfg1_ep_dir4_mask (0x3)
+#define hwcfg1_ep_dir5_shift (10)
+#define hwcfg1_ep_dir5_mask (0x3)
+#define hwcfg1_ep_dir6_shift (12)
+#define hwcfg1_ep_dir6_mask (0x3)
+#define hwcfg1_ep_dir7_shift (14)
+#define hwcfg1_ep_dir7_mask (0x3)
+#define hwcfg1_ep_dir8_shift (16)
+#define hwcfg1_ep_dir8_mask (0x3)
+#define hwcfg1_ep_dir9_shift (18)
+#define hwcfg1_ep_dir9_mask (0x3)
+#define hwcfg1_ep_dir10_shift (20)
+#define hwcfg1_ep_dir10_mask (0x3)
+#define hwcfg1_ep_dir11_shift (22)
+#define hwcfg1_ep_dir11_mask (0x3)
+#define hwcfg1_ep_dir12_shift (24)
+#define hwcfg1_ep_dir12_mask (0x3)
+#define hwcfg1_ep_dir13_shift (26)
+#define hwcfg1_ep_dir13_mask (0x3)
+#define hwcfg1_ep_dir14_shift (28)
+#define hwcfg1_ep_dir14_mask (0x3)
+#define hwcfg1_ep_dir15_shift (30)
+#define hwcfg1_ep_dir15_mask (0x3)
+
+/* union hwcfg2_data */
+#define hwcfg2_op_mode_shift (0)
+#define hwcfg2_op_mode_mask (0x7)
+#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
+#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
+#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
+#define hwcfg2_architecture_shift (3)
+#define hwcfg2_architecture_mask (0x3)
+#define hwcfg2_point2point (1 << 5)
+#define hwcfg2_hs_phy_type_shift (6)
+#define hwcfg2_hs_phy_type_mask (0x3)
+#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
+#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
+#define hwcfg2_fs_phy_type_shift (8)
+#define hwcfg2_fs_phy_type_mask (0x3)
+#define hwcfg2_num_dev_ep_shift (10)
+#define hwcfg2_num_dev_ep_mask (0xf)
+#define hwcfg2_num_host_chan_shift (14)
+#define hwcfg2_num_host_chan_mask (0xf)
+#define hwcfg2_perio_ep_supported (1 << 18)
+#define hwcfg2_dynamic_fifo (1 << 19)
+#define hwcfg2_multi_proc_int (1 << 20)
+#define hwcfg2_reserved21 (1 << 21)
+#define hwcfg2_nonperio_tx_q_depth_shift (22)
+#define hwcfg2_nonperio_tx_q_depth_mask (0x3)
+#define hwcfg2_host_perio_tx_q_depth_shift (24)
+#define hwcfg2_host_perio_tx_q_depth_mask (0x3)
+#define hwcfg2_dev_token_q_depth_shift (26)
+#define hwcfg2_dev_token_q_depth_mask (0x1f)
+#define hwcfg2_otg_enable_ic_usb (1 << 31)
+
+/* union hwcfg3_data */
+#define hwcfg3_xfer_size_cntr_width_shift (0)
+#define hwcfg3_xfer_size_cntr_width_mask (0xf)
+#define hwcfg3_packet_size_cntr_width_shift (4)
+#define hwcfg3_packet_size_cntr_width_mask (0x7)
+#define hwcfg3_otg_func (1 << 7)
+#define hwcfg3_i2c (1 << 8)
+#define hwcfg3_vendor_ctrl_if (1 << 9)
+#define hwcfg3_optional_features (1 << 10)
+#define hwcfg3_synch_reset_type (1 << 11)
+#define hwcfg3_adp_supp (1 << 12)
+#define hwcfg3_otg_enable_hsic (1 << 13)
+#define hwcfg3_bc_support (1 << 14)
+#define hwcfg3_otg_lpm_en (1 << 15)
+#define hwcfg3_dfifo_depth_shift (16)
+#define hwcfg3_dfifo_depth_mask (0xffff)
+
+/* union hwcfg4_data */
+#define hwcfg4_num_dev_perio_in_ep_shift (0)
+#define hwcfg4_num_dev_perio_in_ep_mask (0xf)
+#define hwcfg4_power_optimiz (1 << 4)
+#define hwcfg4_min_ahb_freq (1 << 5)
+#define hwcfg4_hiber (1 << 6)
+#define hwcfg4_xhiber (1 << 7)
+#define hwcfg4_reserved_shift (8)
+#define hwcfg4_reserved_mask (0x3f)
+#define hwcfg4_utmi_phy_data_width_shift (14)
+#define hwcfg4_utmi_phy_data_width_mask (0x3)
+#define hwcfg4_num_dev_mode_ctrl_ep_shift (16)
+#define hwcfg4_num_dev_mode_ctrl_ep_mask (0xf)
+#define hwcfg4_iddig_filt_en (1 << 20)
+#define hwcfg4_vbus_valid_filt_en (1 << 21)
+#define hwcfg4_a_valid_filt_en (1 << 22)
+#define hwcfg4_b_valid_filt_en (1 << 23)
+#define hwcfg4_session_end_filt_en (1 << 24)
+#define hwcfg4_ded_fifo_en (1 << 25)
+#define hwcfg4_num_in_eps_shift (26)
+#define hwcfg4_num_in_eps_mask (0xf)
+#define hwcfg4_desc_dma (1 << 30)
+#define hwcfg4_desc_dma_dyn (1 << 31)
+
+/* union glpmctl_data */
+#define glpmctl_lpm_cap_en (1 << 0)
+#define glpmctl_appl_resp (1 << 1)
+#define glpmctl_hird_shift (2)
+#define glpmctl_hird_mask (0xf)
+#define glpmctl_rem_wkup_en (1 << 6)
+#define glpmctl_en_utmi_sleep (1 << 7)
+#define glpmctl_hird_thres_shift (8)
+#define glpmctl_hird_thres_mask (0x1f)
+#define glpmctl_lpm_resp_shift (13)
+#define glpmctl_lpm_resp_mask (0x3)
+#define glpmctl_prt_sleep_sts (1 << 15)
+#define glpmctl_sleep_state_resumeok (1 << 16)
+#define glpmctl_lpm_chan_index_shift (17)
+#define glpmctl_lpm_chan_index_mask (0xf)
+#define glpmctl_retry_count_shift (21)
+#define glpmctl_retry_count_mask (0x7)
+#define glpmctl_send_lpm (1 << 24)
+#define glpmctl_retry_count_sts_shift (25)
+#define glpmctl_retry_count_sts_mask (0x7)
+#define glpmctl_reserved28_29_shift (28)
+#define glpmctl_reserved28_29_mask (0x3)
+#define glpmctl_hsic_connect (1 << 30)
+#define glpmctl_inv_sel_hsic (1 << 31)
+
+/* union adpctl_data */
+#define adpctl_prb_dschg_shift (0)
+#define adpctl_prb_dschg_mask (0x3)
+#define adpctl_prb_delta_shift (2)
+#define adpctl_prb_delta_mask (0x3)
+#define adpctl_prb_per_shift (4)
+#define adpctl_prb_per_mask (0x3)
+#define adpctl_rtim_shift (6)
+#define adpctl_rtim_mask (0x7ff)
+#define adpctl_enaprb (1 << 17)
+#define adpctl_enasns (1 << 18)
+#define adpctl_adpres (1 << 19)
+#define adpctl_adpen (1 << 20)
+#define adpctl_adp_prb_int (1 << 21)
+#define adpctl_adp_sns_int (1 << 22)
+#define adpctl_adp_tmout_int (1 << 23)
+#define adpctl_adp_prb_int_msk (1 << 24)
+#define adpctl_adp_sns_int_msk (1 << 25)
+#define adpctl_adp_tmout_int_msk (1 << 26)
+#define adpctl_ar_shift (27)
+#define adpctl_ar_mask (0x3)
+#define adpctl_reserved29_31_shift (29)
+#define adpctl_reserved29_31_mask (0x7)
+
+/* union dcfg_data */
+#define dcfg_devspd_shift (0)
+#define dcfg_devspd_mask (0x3)
+#define dcfg_nzstsouthshk (1 << 2)
+#define DWC_DCFG_SEND_STALL 1
+#define dcfg_ena32khzs (1 << 3)
+#define dcfg_devaddr_shift (4)
+#define dcfg_devaddr_mask (0x7f)
+#define dcfg_perfrint_shift (11)
+#define dcfg_perfrint_mask (0x3)
+#define DWC_DCFG_FRAME_INTERVAL_80 0
+#define DWC_DCFG_FRAME_INTERVAL_85 1
+#define DWC_DCFG_FRAME_INTERVAL_90 2
+#define DWC_DCFG_FRAME_INTERVAL_95 3
+#define dcfg_endevoutnak (1 << 13)
+#define dcfg_reserved14_17_shift (14)
+#define dcfg_reserved14_17_mask (0xf)
+#define dcfg_epmscnt_shift (18)
+#define dcfg_epmscnt_mask (0x1f)
+#define dcfg_descdma (1 << 23)
+#define dcfg_perschintvl_shift (24)
+#define dcfg_perschintvl_mask (0x3)
+#define dcfg_resvalid_shift (26)
+#define dcfg_resvalid_mask (0x3f)
+
+/* union dctl_data */
+#define dctl_rmtwkupsig (1 << 0)
+#define dctl_sftdiscon (1 << 1)
+#define dctl_gnpinnaksts (1 << 2)
+#define dctl_goutnaksts (1 << 3)
+#define dctl_tstctl_shift (4)
+#define dctl_tstctl_mask (0x7)
+#define dctl_sgnpinnak (1 << 7)
+#define dctl_cgnpinnak (1 << 8)
+#define dctl_sgoutnak (1 << 9)
+#define dctl_cgoutnak (1 << 10)
+#define dctl_pwronprgdone (1 << 11)
+#define dctl_reserved (1 << 12)
+#define dctl_gmc_shift (13)
+#define dctl_gmc_mask (0x3)
+#define dctl_ifrmnum (1 << 15)
+#define dctl_nakonbble (1 << 16)
+#define dctl_encontonbna (1 << 17)
+#define dctl_reserved18_31_shift (18)
+#define dctl_reserved18_31_mask (0x3fff)
+
+/* union dsts_data */
+#define dsts_suspsts (1 << 0)
+#define dsts_enumspd_shift (1)
+#define dsts_enumspd_mask (0x3)
+#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
+#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
+#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ           2
+#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ           3
+#define dsts_errticerr (1 << 3)
+#define dsts_reserved4_7_shift (4)
+#define dsts_reserved4_7_mask (0xf)
+#define dsts_soffn_shift (8)
+#define dsts_soffn_mask (0x3fff)
+#define dsts_reserved22_31_shift (22)
+#define dsts_reserved22_31_mask (0x3ff)
+
+/* union diepint_data */
+#define diepint_xfercompl (1 << 0)
+#define diepint_epdisabled (1 << 1)
+#define diepint_ahberr (1 << 2)
+#define diepint_timeout (1 << 3)
+#define diepint_intktxfemp (1 << 4)
+#define diepint_intknepmis (1 << 5)
+#define diepint_inepnakeff (1 << 6)
+#define diepint_emptyintr (1 << 7)
+#define diepint_txfifoundrn (1 << 8)
+#define diepint_bna (1 << 9)
+#define diepint_reserved10_12_shift (10)
+#define diepint_reserved10_12_mask (0x7)
+#define diepint_nak (1 << 13)
+#define diepint_reserved14_31_shift (14)
+#define diepint_reserved14_31_mask (0x3ffff)
+
+/* union doepint_data */
+#define doepint_xfercompl (1 << 0)
+#define doepint_epdisabled (1 << 1)
+#define doepint_ahberr (1 << 2)
+#define doepint_setup (1 << 3)
+#define doepint_outtknepdis (1 << 4)
+#define doepint_stsphsercvd (1 << 5)
+#define doepint_back2backsetup (1 << 6)
+#define doepint_reserved7 (1 << 7)
+#define doepint_outpkterr (1 << 8)
+#define doepint_bna (1 << 9)
+#define doepint_reserved10 (1 << 10)
+#define doepint_pktdrpsts (1 << 11)
+#define doepint_babble (1 << 12)
+#define doepint_nak (1 << 13)
+#define doepint_nyet (1 << 14)
+#define doepint_sr (1 << 15)
+#define doepint_reserved16_31_shift (16)
+#define doepint_reserved16_31_mask (0xffff)
+
+/* union daint_data */
+#define daint_in_shift (0)
+#define daint_in_mask (0xffff)
+#define daint_out_shift (16)
+#define daint_out_mask (0xffff)
+#define daint_b_inep0 (1 << 0)
+#define daint_b_inep1 (1 << 1)
+#define daint_b_inep2 (1 << 2)
+#define daint_b_inep3 (1 << 3)
+#define daint_b_inep4 (1 << 4)
+#define daint_b_inep5 (1 << 5)
+#define daint_b_inep6 (1 << 6)
+#define daint_b_inep7 (1 << 7)
+#define daint_b_inep8 (1 << 8)
+#define daint_b_inep9 (1 << 9)
+#define daint_b_inep10 (1 << 10)
+#define daint_b_inep11 (1 << 11)
+#define daint_b_inep12 (1 << 12)
+#define daint_b_inep13 (1 << 13)
+#define daint_b_inep14 (1 << 14)
+#define daint_b_inep15 (1 << 15)
+#define daint_b_outep0 (1 << 16)
+#define daint_b_outep1 (1 << 17)
+#define daint_b_outep2 (1 << 18)
+#define daint_b_outep3 (1 << 19)
+#define daint_b_outep4 (1 << 20)
+#define daint_b_outep5 (1 << 21)
+#define daint_b_outep6 (1 << 22)
+#define daint_b_outep7 (1 << 23)
+#define daint_b_outep8 (1 << 24)
+#define daint_b_outep9 (1 << 25)
+#define daint_b_outep10 (1 << 26)
+#define daint_b_outep11 (1 << 27)
+#define daint_b_outep12 (1 << 28)
+#define daint_b_outep13 (1 << 29)
+#define daint_b_outep14 (1 << 30)
+#define daint_b_outep15 (1 << 31)
+
+/* union dtknq1_data */
+#define dtknq1_intknwptr_shift (0)
+#define dtknq1_intknwptr_mask (0x1f)
+#define dtknq1_reserved05_06_shift (5)
+#define dtknq1_reserved05_06_mask (0x3)
+#define dtknq1_wrap_bit (1 << 7)
+#define dtknq1_epnums0_5_shift (8)
+#define dtknq1_epnums0_5_mask (0xffffff)
+
+/* union dthrctl_data */
+#define dthrctl_non_iso_thr_en (1 << 0)
+#define dthrctl_iso_thr_en (1 << 1)
+#define dthrctl_tx_thr_len_shift (2)
+#define dthrctl_tx_thr_len_mask (0x1ff)
+#define dthrctl_ahb_thr_ratio_shift (11)
+#define dthrctl_ahb_thr_ratio_mask (0x3)
+#define dthrctl_reserved13_15_shift (13)
+#define dthrctl_reserved13_15_mask (0x7)
+#define dthrctl_rx_thr_en (1 << 16)
+#define dthrctl_rx_thr_len_shift (17)
+#define dthrctl_rx_thr_len_mask (0x1ff)
+#define dthrctl_reserved26 (1 << 26)
+#define dthrctl_arbprken (1 << 27)
+#define dthrctl_reserved28_31_shift (28)
+#define dthrctl_reserved28_31_mask (0xf)
+
+/* union depctl_data */
+#define depctl_mps_shift (0)
+#define depctl_mps_mask (0x7ff)
+#define DWC_DEP0CTL_MPS_64     0
+#define DWC_DEP0CTL_MPS_32     1
+#define DWC_DEP0CTL_MPS_16     2
+#define DWC_DEP0CTL_MPS_8     3
+#define depctl_nextep_shift (11)
+#define depctl_nextep_mask (0xf)
+#define depctl_usbactep (1 << 15)
+#define depctl_dpid (1 << 16)
+#define depctl_naksts (1 << 17)
+#define depctl_eptype_shift (18)
+#define depctl_eptype_mask (0x3)
+#define depctl_snp (1 << 20)
+#define depctl_stall (1 << 21)
+#define depctl_txfnum_shift (22)
+#define depctl_txfnum_mask (0xf)
+#define depctl_cnak (1 << 26)
+#define depctl_snak (1 << 27)
+#define depctl_setd0pid (1 << 28)
+#define depctl_setd1pid (1 << 29)
+#define depctl_epdis (1 << 30)
+#define depctl_epena (1 << 31)
+
+/* union deptsiz_data */
+#define deptsiz_xfersize_shift (0)
+#define deptsiz_xfersize_mask (0x7ffff)
+#define MAX_PKT_CNT 1023
+#define deptsiz_pktcnt_shift (19)
+#define deptsiz_pktcnt_mask (0x3ff)
+#define deptsiz_mc_shift (29)
+#define deptsiz_mc_mask (0x3)
+#define deptsiz_reserved (1 << 31)
+
+/* union deptsiz0_data */
+#define deptsiz0_xfersize_shift (0)
+#define deptsiz0_xfersize_mask (0x7f)
+#define deptsiz0_reserved7_18_shift (7)
+#define deptsiz0_reserved7_18_mask (0xfff)
+#define deptsiz0_pktcnt_shift (19)
+#define deptsiz0_pktcnt_mask (0x3)
+#define deptsiz0_reserved21_28_shift (21)
+#define deptsiz0_reserved21_28_mask (0xff)
+#define deptsiz0_supcnt_shift (29)
+#define deptsiz0_supcnt_mask (0x3)
+#define deptsiz0_reserved31 (1 << 31)
+#define BS_HOST_READY    0x0
+#define BS_DMA_BUSY        0x1
+#define BS_DMA_DONE        0x2
+#define BS_HOST_BUSY    0x3
+#define RTS_SUCCESS        0x0
+#define RTS_BUFFLUSH    0x1
+#define RTS_RESERVED    0x2
+#define RTS_BUFERR        0x3
+
+/* union dev_dma_desc_sts */
+#define dev_dma_desc_sts_bytes_shift (0)
+#define dev_dma_desc_sts_bytes_mask (0xffff)
+#define dev_dma_desc_sts_nak (1 << 16)
+#define dev_dma_desc_sts_reserved17_22_shift (17)
+#define dev_dma_desc_sts_reserved17_22_mask (0x3f)
+#define dev_dma_desc_sts_mtrf (1 << 23)
+#define dev_dma_desc_sts_sr (1 << 24)
+#define dev_dma_desc_sts_ioc (1 << 25)
+#define dev_dma_desc_sts_sp (1 << 26)
+#define dev_dma_desc_sts_l (1 << 27)
+#define dev_dma_desc_sts_sts_shift (28)
+#define dev_dma_desc_sts_sts_mask (0x3)
+#define dev_dma_desc_sts_bs_shift (30)
+#define dev_dma_desc_sts_bs_mask (0x3)
+#define dev_dma_desc_sts_b_rxbytes_shift (0)
+#define dev_dma_desc_sts_b_rxbytes_mask (0x7ff)
+#define dev_dma_desc_sts_b_reserved11 (1 << 11)
+#define dev_dma_desc_sts_b_framenum_shift (12)
+#define dev_dma_desc_sts_b_framenum_mask (0x7ff)
+#define dev_dma_desc_sts_b_pid_shift (23)
+#define dev_dma_desc_sts_b_pid_mask (0x3)
+#define dev_dma_desc_sts_b_ioc (1 << 25)
+#define dev_dma_desc_sts_b_sp (1 << 26)
+#define dev_dma_desc_sts_b_l (1 << 27)
+#define dev_dma_desc_sts_b_rxsts_shift (28)
+#define dev_dma_desc_sts_b_rxsts_mask (0x3)
+#define dev_dma_desc_sts_b_bs_shift (30)
+#define dev_dma_desc_sts_b_bs_mask (0x3)
+#define dev_dma_desc_sts_b_b_txbytes_shift (0)
+#define dev_dma_desc_sts_b_b_txbytes_mask (0xfff)
+#define dev_dma_desc_sts_b_b_framenum_shift (12)
+#define dev_dma_desc_sts_b_b_framenum_mask (0x7ff)
+#define dev_dma_desc_sts_b_b_pid_shift (23)
+#define dev_dma_desc_sts_b_b_pid_mask (0x3)
+#define dev_dma_desc_sts_b_b_ioc (1 << 25)
+#define dev_dma_desc_sts_b_b_sp (1 << 26)
+#define dev_dma_desc_sts_b_b_l (1 << 27)
+#define dev_dma_desc_sts_b_b_txsts_shift (28)
+#define dev_dma_desc_sts_b_b_txsts_mask (0x3)
+#define dev_dma_desc_sts_b_b_bs_shift (30)
+#define dev_dma_desc_sts_b_b_bs_mask (0x3)
+#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
+#define DWC_DEV_IN_EP_REG_OFFSET 0x900
+#define DWC_EP_REG_OFFSET 0x20
+#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
+
+/* union hcfg_data */
+#define hcfg_fslspclksel_shift (0)
+#define hcfg_fslspclksel_mask (0x3)
+#define DWC_HCFG_30_60_MHZ 0
+#define DWC_HCFG_48_MHZ       1
+#define DWC_HCFG_6_MHZ       2
+#define hcfg_fslssupp (1 << 2)
+#define hcfg_reserved3_6_shift (3)
+#define hcfg_reserved3_6_mask (0xf)
+#define hcfg_ena32khzs (1 << 7)
+#define hcfg_resvalid_shift (8)
+#define hcfg_resvalid_mask (0xff)
+#define hcfg_reserved16_22_shift (16)
+#define hcfg_reserved16_22_mask (0x7f)
+#define hcfg_descdma (1 << 23)
+#define hcfg_frlisten_shift (24)
+#define hcfg_frlisten_mask (0x3)
+#define hcfg_perschedena (1 << 26)
+#define hcfg_reserved27_30_shift (27)
+#define hcfg_reserved27_30_mask (0xf)
+#define hcfg_modechtimen (1 << 31)
+
+/* union hfir_data */
+#define hfir_frint_shift (0)
+#define hfir_frint_mask (0xffff)
+#define hfir_hfirrldctrl (1 << 16)
+#define hfir_reserved_shift (17)
+#define hfir_reserved_mask (0x7fff)
+
+/* union hfnum_data */
+#define hfnum_frnum_shift (0)
+#define hfnum_frnum_mask (0xffff)
+#define DWC_HFNUM_MAX_FRNUM 0x3FFF
+#define hfnum_frrem_shift (16)
+#define hfnum_frrem_mask (0xffff)
+
+/* union hptxsts_data */
+#define hptxsts_ptxfspcavail_shift (0)
+#define hptxsts_ptxfspcavail_mask (0xffff)
+#define hptxsts_ptxqspcavail_shift (16)
+#define hptxsts_ptxqspcavail_mask (0xff)
+#define hptxsts_ptxqtop_terminate (1 << 24)
+#define hptxsts_ptxqtop_token_shift (25)
+#define hptxsts_ptxqtop_token_mask (0x3)
+#define hptxsts_ptxqtop_chnum_shift (27)
+#define hptxsts_ptxqtop_chnum_mask (0xf)
+#define hptxsts_ptxqtop_odd (1 << 31)
+
+/* union hprt0_data */
+#define hprt0_prtconnsts (1 << 0)
+#define hprt0_prtconndet (1 << 1)
+#define hprt0_prtena (1 << 2)
+#define hprt0_prtenchng (1 << 3)
+#define hprt0_prtovrcurract (1 << 4)
+#define hprt0_prtovrcurrchng (1 << 5)
+#define hprt0_prtres (1 << 6)
+#define hprt0_prtsusp (1 << 7)
+#define hprt0_prtrst (1 << 8)
+#define hprt0_reserved9 (1 << 9)
+#define hprt0_prtlnsts_shift (10)
+#define hprt0_prtlnsts_mask (0x3)
+#define hprt0_prtpwr (1 << 12)
+#define hprt0_prttstctl_shift (13)
+#define hprt0_prttstctl_mask (0xf)
+#define hprt0_prtspd_shift (17)
+#define hprt0_prtspd_mask (0x3)
+#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
+#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
+#define DWC_HPRT0_PRTSPD_LOW_SPEED    2
+#define hprt0_reserved19_31_shift (19)
+#define hprt0_reserved19_31_mask (0x1fff)
+
+/* union haint_data */
+#define haint_ch0 (1 << 0)
+#define haint_ch1 (1 << 1)
+#define haint_ch2 (1 << 2)
+#define haint_ch3 (1 << 3)
+#define haint_ch4 (1 << 4)
+#define haint_ch5 (1 << 5)
+#define haint_ch6 (1 << 6)
+#define haint_ch7 (1 << 7)
+#define haint_ch8 (1 << 8)
+#define haint_ch9 (1 << 9)
+#define haint_ch10 (1 << 10)
+#define haint_ch11 (1 << 11)
+#define haint_ch12 (1 << 12)
+#define haint_ch13 (1 << 13)
+#define haint_ch14 (1 << 14)
+#define haint_ch15 (1 << 15)
+#define haint_reserved_shift (16)
+#define haint_reserved_mask (0xffff)
+#define haint_b_chint_shift (0)
+#define haint_b_chint_mask (0xffff)
+#define haint_b_reserved_shift (16)
+#define haint_b_reserved_mask (0xffff)
+
+/* union haintmsk_data */
+#define haintmsk_ch0 (1 << 0)
+#define haintmsk_ch1 (1 << 1)
+#define haintmsk_ch2 (1 << 2)
+#define haintmsk_ch3 (1 << 3)
+#define haintmsk_ch4 (1 << 4)
+#define haintmsk_ch5 (1 << 5)
+#define haintmsk_ch6 (1 << 6)
+#define haintmsk_ch7 (1 << 7)
+#define haintmsk_ch8 (1 << 8)
+#define haintmsk_ch9 (1 << 9)
+#define haintmsk_ch10 (1 << 10)
+#define haintmsk_ch11 (1 << 11)
+#define haintmsk_ch12 (1 << 12)
+#define haintmsk_ch13 (1 << 13)
+#define haintmsk_ch14 (1 << 14)
+#define haintmsk_ch15 (1 << 15)
+#define haintmsk_reserved_shift (16)
+#define haintmsk_reserved_mask (0xffff)
+#define haintmsk_b_chint_shift (0)
+#define haintmsk_b_chint_mask (0xffff)
+#define haintmsk_b_reserved_shift (16)
+#define haintmsk_b_reserved_mask (0xffff)
+
+/* union hcchar_data */
+#define hcchar_mps_shift (0)
+#define hcchar_mps_mask (0x7ff)
+#define hcchar_epnum_shift (11)
+#define hcchar_epnum_mask (0xf)
+#define hcchar_epdir (1 << 15)
+#define hcchar_reserved (1 << 16)
+#define hcchar_lspddev (1 << 17)
+#define hcchar_eptype_shift (18)
+#define hcchar_eptype_mask (0x3)
+#define hcchar_multicnt_shift (20)
+#define hcchar_multicnt_mask (0x3)
+#define hcchar_devaddr_shift (22)
+#define hcchar_devaddr_mask (0x7f)
+#define hcchar_oddfrm (1 << 29)
+#define hcchar_chdis (1 << 30)
+#define hcchar_chen (1 << 31)
+
+/* union hcsplt_data */
+#define hcsplt_prtaddr_shift (0)
+#define hcsplt_prtaddr_mask (0x7f)
+#define hcsplt_hubaddr_shift (7)
+#define hcsplt_hubaddr_mask (0x7f)
+#define hcsplt_xactpos_shift (14)
+#define hcsplt_xactpos_mask (0x3)
+#define DWC_HCSPLIT_XACTPOS_MID 0
+#define DWC_HCSPLIT_XACTPOS_END 1
+#define DWC_HCSPLIT_XACTPOS_BEGIN 2
+#define DWC_HCSPLIT_XACTPOS_ALL 3
+#define hcsplt_compsplt (1 << 16)
+#define hcsplt_reserved_shift (17)
+#define hcsplt_reserved_mask (0x3fff)
+#define hcsplt_spltena (1 << 31)
+
+/* union hcint_data */
+#define hcint_xfercomp (1 << 0)
+#define hcint_chhltd (1 << 1)
+#define hcint_ahberr (1 << 2)
+#define hcint_stall (1 << 3)
+#define hcint_nak (1 << 4)
+#define hcint_ack (1 << 5)
+#define hcint_nyet (1 << 6)
+#define hcint_xacterr (1 << 7)
+#define hcint_bblerr (1 << 8)
+#define hcint_frmovrun (1 << 9)
+#define hcint_datatglerr (1 << 10)
+#define hcint_bna (1 << 11)
+#define hcint_xcs_xact (1 << 12)
+#define hcint_frm_list_roll (1 << 13)
+#define hcint_reserved14_31_shift (14)
+#define hcint_reserved14_31_mask (0x3ffff)
+
+/* union hcintmsk_data */
+#define hcintmsk_xfercompl (1 << 0)
+#define hcintmsk_chhltd (1 << 1)
+#define hcintmsk_ahberr (1 << 2)
+#define hcintmsk_stall (1 << 3)
+#define hcintmsk_nak (1 << 4)
+#define hcintmsk_ack (1 << 5)
+#define hcintmsk_nyet (1 << 6)
+#define hcintmsk_xacterr (1 << 7)
+#define hcintmsk_bblerr (1 << 8)
+#define hcintmsk_frmovrun (1 << 9)
+#define hcintmsk_datatglerr (1 << 10)
+#define hcintmsk_bna (1 << 11)
+#define hcintmsk_xcs_xact (1 << 12)
+#define hcintmsk_frm_list_roll (1 << 13)
+#define hcintmsk_reserved14_31_shift (14)
+#define hcintmsk_reserved14_31_mask (0x3ffff)
+
+/* union hctsiz_data */
+#define hctsiz_xfersize_shift (0)
+#define hctsiz_xfersize_mask (0x7ffff)
+#define hctsiz_pktcnt_shift (19)
+#define hctsiz_pktcnt_mask (0x3ff)
+#define hctsiz_pid_shift (29)
+#define hctsiz_pid_mask (0x3)
+#define DWC_HCTSIZ_DATA0 0
+#define DWC_HCTSIZ_DATA1 2
+#define DWC_HCTSIZ_DATA2 1
+#define DWC_HCTSIZ_MDATA 3
+#define DWC_HCTSIZ_SETUP 3
+#define hctsiz_dopng (1 << 31)
+#define hctsiz_b_schinfo_shift (0)
+#define hctsiz_b_schinfo_mask (0xff)
+#define hctsiz_b_ntd_shift (8)
+#define hctsiz_b_ntd_mask (0xff)
+#define hctsiz_b_reserved16_28_shift (16)
+#define hctsiz_b_reserved16_28_mask (0x1fff)
+#define hctsiz_b_pid_shift (29)
+#define hctsiz_b_pid_mask (0x3)
+#define hctsiz_b_dopng (1 << 31)
+
+/* union hcdma_data */
+#define hcdma_reserved0_2_shift (0)
+#define hcdma_reserved0_2_mask (0x7)
+#define hcdma_ctd_shift (3)
+#define hcdma_ctd_mask (0xff)
+#define hcdma_dma_addr_shift (11)
+#define hcdma_dma_addr_mask (0x1fffff)
+
+/* union host_dma_desc_sts */
+#define host_dma_desc_sts_n_bytes_shift (0)
+#define host_dma_desc_sts_n_bytes_mask (0x1ffff)
+#define host_dma_desc_sts_qtd_offset_shift (17)
+#define host_dma_desc_sts_qtd_offset_mask (0x3f)
+#define host_dma_desc_sts_a_qtd (1 << 23)
+#define host_dma_desc_sts_sup (1 << 24)
+#define host_dma_desc_sts_ioc (1 << 25)
+#define host_dma_desc_sts_eol (1 << 26)
+#define host_dma_desc_sts_reserved27 (1 << 27)
+#define host_dma_desc_sts_sts_shift (28)
+#define host_dma_desc_sts_sts_mask (0x3)
+#define DMA_DESC_STS_PKTERR    1
+#define host_dma_desc_sts_reserved30 (1 << 30)
+#define host_dma_desc_sts_a (1 << 31)
+#define host_dma_desc_sts_b_n_bytes_shift (0)
+#define host_dma_desc_sts_b_n_bytes_mask (0xfff)
+#define host_dma_desc_sts_b_reserved12_24_shift (12)
+#define host_dma_desc_sts_b_reserved12_24_mask (0x1fff)
+#define host_dma_desc_sts_b_ioc (1 << 25)
+#define host_dma_desc_sts_b_reserved26_27_shift (26)
+#define host_dma_desc_sts_b_reserved26_27_mask (0x3)
+#define host_dma_desc_sts_b_sts_shift (28)
+#define host_dma_desc_sts_b_sts_mask (0x3)
+#define host_dma_desc_sts_b_reserved30 (1 << 30)
+#define host_dma_desc_sts_b_a (1 << 31)
+#define    MAX_DMA_DESC_SIZE        131071
+#define MAX_DMA_DESC_NUM_GENERIC    64
+#define MAX_DMA_DESC_NUM_HS_ISOC    256
+#define MAX_FRLIST_EN_NUM        64
+#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
+#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
+#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
+#define DWC_OTG_CHAN_REGS_OFFSET 0x20
+
+/* union pcgcctl_data */
+#define pcgcctl_stoppclk (1 << 0)
+#define pcgcctl_gatehclk (1 << 1)
+#define pcgcctl_pwrclmp (1 << 2)
+#define pcgcctl_rstpdwnmodule (1 << 3)
+#define pcgcctl_reserved (1 << 4)
+#define pcgcctl_enbl_sleep_gating (1 << 5)
+#define pcgcctl_phy_in_sleep (1 << 6)
+#define pcgcctl_deep_sleep (1 << 7)
+#define pcgcctl_resetaftsusp (1 << 8)
+#define pcgcctl_restoremode (1 << 9)
+#define pcgcctl_enbl_extnd_hiber (1 << 10)
+#define pcgcctl_extnd_hiber_pwrclmp (1 << 11)
+#define pcgcctl_extnd_hiber_switch (1 << 12)
+#define pcgcctl_ess_reg_restored (1 << 13)
+#define pcgcctl_prt_clk_sel_shift (14)
+#define pcgcctl_prt_clk_sel_mask (0x3)
+#define pcgcctl_port_power (1 << 16)
+#define pcgcctl_max_xcvrselect_shift (17)
+#define pcgcctl_max_xcvrselect_mask (0x3)
+#define pcgcctl_max_termsel (1 << 19)
+#define pcgcctl_mac_dev_addr_shift (20)
+#define pcgcctl_mac_dev_addr_mask (0x7f)
+#define pcgcctl_p2hd_dev_enum_spd_shift (27)
+#define pcgcctl_p2hd_dev_enum_spd_mask (0x3)
+#define pcgcctl_p2hd_prt_spd_shift (29)
+#define pcgcctl_p2hd_prt_spd_mask (0x3)
+#define pcgcctl_if_dev_mode (1 << 31)
+
+/* union gdfifocfg_data */
+#define gdfifocfg_gdfifocfg_shift (0)
+#define gdfifocfg_gdfifocfg_mask (0xffff)
+#define gdfifocfg_epinfobase_shift (16)
+#define gdfifocfg_epinfobase_mask (0xffff)
+
+/* union gpwrdn_data */
+#define gpwrdn_pmuintsel (1 << 0)
+#define gpwrdn_pmuactv (1 << 1)
+#define gpwrdn_restore (1 << 2)
+#define gpwrdn_pwrdnclmp (1 << 3)
+#define gpwrdn_pwrdnrstn (1 << 4)
+#define gpwrdn_pwrdnswtch (1 << 5)
+#define gpwrdn_dis_vbus (1 << 6)
+#define gpwrdn_lnstschng (1 << 7)
+#define gpwrdn_lnstchng_msk (1 << 8)
+#define gpwrdn_rst_det (1 << 9)
+#define gpwrdn_rst_det_msk (1 << 10)
+#define gpwrdn_disconn_det (1 << 11)
+#define gpwrdn_disconn_det_msk (1 << 12)
+#define gpwrdn_connect_det (1 << 13)
+#define gpwrdn_connect_det_msk (1 << 14)
+#define gpwrdn_srp_det (1 << 15)
+#define gpwrdn_srp_det_msk (1 << 16)
+#define gpwrdn_sts_chngint (1 << 17)
+#define gpwrdn_sts_chngint_msk (1 << 18)
+#define gpwrdn_linestate_shift (19)
+#define gpwrdn_linestate_mask (0x3)
+#define gpwrdn_idsts (1 << 21)
+#define gpwrdn_bsessvld (1 << 22)
+#define gpwrdn_adp_int (1 << 23)
+#define gpwrdn_mult_val_id_bc_shift (24)
+#define gpwrdn_mult_val_id_bc_mask (0x1f)
+#define gpwrdn_reserved29_31_shift (29)
+#define gpwrdn_reserved29_31_mask (0x7)
+
+#endif /* BCM2835_USB_REGS_H */
diff --git a/hw/arm/bcm2835_vchiq.c b/hw/arm/bcm2835_vchiq.c
new file mode 100644
index 0000000..1bb3edb
--- /dev/null
+++ b/hw/arm/bcm2835_vchiq.c
@@ -0,0 +1,117 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+
+#include "bcm2835_common.h"
+
+#define TYPE_BCM2835_VCHIQ "bcm2835_vchiq"
+#define BCM2835_VCHIQ(obj) \
+        OBJECT_CHECK(bcm2835_vchiq_state, (obj), TYPE_BCM2835_VCHIQ)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    int pending;
+    qemu_irq mbox_irq;
+} bcm2835_vchiq_state;
+
+static uint64_t bcm2835_vchiq_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    bcm2835_vchiq_state *s = (bcm2835_vchiq_state *)opaque;
+    uint32_t res = 0;
+
+    switch (offset) {
+    case 0:
+        res = MBOX_CHAN_VCHIQ;
+        s->pending = 0;
+        qemu_set_irq(s->mbox_irq, 0);
+        break;
+    case 4:
+        res = s->pending;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_vchiq_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+    return res;
+}
+static void bcm2835_vchiq_write(void *opaque, hwaddr offset,
+    uint64_t value, unsigned size)
+{
+    bcm2835_vchiq_state *s = (bcm2835_vchiq_state *)opaque;
+    switch (offset) {
+    case 0:
+        s->pending = 1;
+        qemu_set_irq(s->mbox_irq, 1);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_vchiq_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+
+}
+
+
+static const MemoryRegionOps bcm2835_vchiq_ops = {
+    .read = bcm2835_vchiq_read,
+    .write = bcm2835_vchiq_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+
+static const VMStateDescription vmstate_bcm2835_vchiq = {
+    .name = "bcm2835_vchiq",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bcm2835_vchiq_init(SysBusDevice *sbd)
+{
+    /* bcm2835_vchiq_state *s = FROM_SYSBUS(bcm2835_vchiq_state, dev); */
+    DeviceState *dev = DEVICE(sbd);
+    bcm2835_vchiq_state *s = BCM2835_VCHIQ(dev);
+
+    s->pending = 0;
+
+    sysbus_init_irq(sbd, &s->mbox_irq);
+    memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_vchiq_ops, s,
+        "bcm2835_vchiq", 0x10);
+    sysbus_init_mmio(sbd, &s->iomem);
+    vmstate_register(dev, -1, &vmstate_bcm2835_vchiq, s);
+
+    return 0;
+}
+
+static void bcm2835_vchiq_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    /* DeviceClass *k = DEVICE_CLASS(klass); */
+
+    sdc->init = bcm2835_vchiq_init;
+}
+
+static TypeInfo bcm2835_vchiq_info = {
+    .name          = "bcm2835_vchiq",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(bcm2835_vchiq_state),
+    .class_init    = bcm2835_vchiq_class_init,
+};
+
+static void bcm2835_vchiq_register_types(void)
+{
+    type_register_static(&bcm2835_vchiq_info);
+}
+
+type_init(bcm2835_vchiq_register_types)
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
new file mode 100644
index 0000000..0a88acc
--- /dev/null
+++ b/hw/arm/raspi.c
@@ -0,0 +1,361 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+/* Based on versatilepb.c, copyright terms below. */
+
+/*
+ * ARM Versatile Platform/Application Baseboard System emulation.
+ *
+ * Copyright (c) 2005-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm/arm.h"
+#include "hw/devices.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+#include "bcm2835_common.h"
+
+#define BUS_ADDR(x) (((x) - BCM2708_PERI_BASE) + 0x7e000000)
+
+/* Globals */
+hwaddr bcm2835_vcram_base;
+
+const uint32_t bootloader_0[] = {
+0xea000006,
+0xe1a00000,
+0xe1a00000,
+0xe1a00000,
+0xe1a00000,
+0xe1a00000,
+0xe1a00000,
+0xe1a00000,
+
+0xe3a00000,
+0xe3a01042,
+0xe3811c0c,
+0xe59f2000,
+0xe59ff000,
+0x00000100,
+0x00008000
+};
+
+uint32_t bootloader_100[] = {
+0x00000005,
+0x54410001,
+0x00000001,
+0x00001000,
+0x00000000,
+0x00000004,
+0x54410002,
+0x08000000, /* It will be overwritten by dynamically calculated memory size */
+0x00000000,
+0x00000000,
+0x00000000
+};
+
+
+static struct arm_boot_info raspi_binfo;
+
+static void raspi_init(QEMUMachineInitArgs *args)
+{
+    ARMCPU *cpu;
+    MemoryRegion *sysmem = get_system_memory();
+
+    MemoryRegion *bcm2835_ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bcm2835_vcram = g_new(MemoryRegion, 1);
+
+    MemoryRegion *ram_alias = g_new(MemoryRegion, 4);
+    MemoryRegion *vcram_alias = g_new(MemoryRegion, 4);
+
+    MemoryRegion *per_todo_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_ic_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_uart_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_st_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_sbm_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_power_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_fb_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_prop_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_vchiq_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_emmc_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_dma1_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_dma2_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_timer_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_usb_bus = g_new(MemoryRegion, 1);
+    MemoryRegion *per_mphi_bus = g_new(MemoryRegion, 1);
+
+    MemoryRegion *mr;
+
+    /* qemu_irq *cpu_pic; */
+    qemu_irq pic[72];
+    qemu_irq mbox_irq[MBOX_CHAN_COUNT];
+
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    int n;
+
+    cpu = cpu_arm_init("arm1176");
+    if (!cpu) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+
+    bcm2835_vcram_base = args->ram_size - VCRAM_SIZE;
+
+    /* Write real RAM size in ATAG structure */
+    bootloader_100[7] = bcm2835_vcram_base;
+
+    memory_region_init_ram(bcm2835_ram, NULL, "raspi.ram", bcm2835_vcram_base);
+    vmstate_register_ram_global(bcm2835_ram);
+
+    memory_region_init_ram(bcm2835_vcram, NULL, "vcram.ram", VCRAM_SIZE);
+    vmstate_register_ram_global(bcm2835_vcram);
+
+    memory_region_add_subregion(sysmem, (0 << 30), bcm2835_ram);
+    memory_region_add_subregion(sysmem, (0 << 30) + bcm2835_vcram_base,
+        bcm2835_vcram);
+    for (n = 1; n < 4; n++) {
+        memory_region_init_alias(&ram_alias[n], NULL, NULL, bcm2835_ram,
+            0, bcm2835_vcram_base);
+        memory_region_init_alias(&vcram_alias[n], NULL, NULL, bcm2835_vcram,
+            0, VCRAM_SIZE);
+        memory_region_add_subregion(sysmem, (n << 30), &ram_alias[n]);
+        memory_region_add_subregion(sysmem, (n << 30) + bcm2835_vcram_base,
+            &vcram_alias[n]);
+    }
+
+    /* (Yet) unmapped I/O registers */
+    dev = sysbus_create_simple("bcm2835_todo", BCM2708_PERI_BASE, NULL);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_todo_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(BCM2708_PERI_BASE),
+        per_todo_bus);
+
+    /* Interrupt Controller */
+    /* cpu_pic = arm_pic_init_cpu(cpu);
+    dev = sysbus_create_varargs("bcm2835_ic", ARMCTRL_IC_BASE,
+        cpu_pic[ARM_PIC_CPU_IRQ],
+        cpu_pic[ARM_PIC_CPU_FIQ], NULL);*/
+    dev = sysbus_create_varargs("bcm2835_ic", ARMCTRL_IC_BASE,
+        qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
+        qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), NULL);
+
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_ic_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(ARMCTRL_IC_BASE),
+        per_ic_bus);
+    for (n = 0; n < 72; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    /* UART */
+    dev = sysbus_create_simple("pl011", UART0_BASE, pic[INTERRUPT_VC_UART]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_uart_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(UART0_BASE),
+        per_uart_bus);
+
+
+    /* System timer */
+    dev = sysbus_create_varargs("bcm2835_st", ST_BASE,
+            pic[INTERRUPT_TIMER0], pic[INTERRUPT_TIMER1],
+            pic[INTERRUPT_TIMER2], pic[INTERRUPT_TIMER3],
+            NULL);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_st_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(ST_BASE),
+        per_st_bus);
+
+    /* ARM timer */
+    dev = sysbus_create_simple("bcm2835_timer", ARMCTRL_TIMER0_1_BASE,
+        pic[INTERRUPT_ARM_TIMER]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_timer_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(ARMCTRL_TIMER0_1_BASE),
+        per_timer_bus);
+
+    /* USB controller */
+    dev = sysbus_create_simple("bcm2835_usb", USB_BASE,
+        pic[INTERRUPT_VC_USB]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_usb_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(USB_BASE),
+        per_usb_bus);
+
+    /* MPHI - Message-based Parallel Host Interface */
+    dev = sysbus_create_simple("bcm2835_mphi", MPHI_BASE,
+        pic[INTERRUPT_HOSTPORT]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_mphi_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(MPHI_BASE),
+        per_mphi_bus);
+
+
+    /* Semaphores / Doorbells / Mailboxes */
+    dev = sysbus_create_simple("bcm2835_sbm", ARMCTRL_0_SBM_BASE,
+        pic[INTERRUPT_ARM_MAILBOX]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_sbm_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(ARMCTRL_0_SBM_BASE),
+        per_sbm_bus);
+
+    for (n = 0; n < MBOX_CHAN_COUNT; n++) {
+        mbox_irq[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    /* Mailbox-addressable peripherals using (hopefully) free address space */
+    /* locations and pseudo-irqs to dispatch mailbox requests and responses */
+    /* between them. */
+
+    /* Power management */
+    dev = sysbus_create_simple("bcm2835_power",
+        ARMCTRL_0_SBM_BASE + 0x400 + (MBOX_CHAN_POWER<<4),
+        mbox_irq[MBOX_CHAN_POWER]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_power_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem,
+        BUS_ADDR(ARMCTRL_0_SBM_BASE + 0x400 + (MBOX_CHAN_POWER<<4)),
+        per_power_bus);
+
+    /* Framebuffer */
+    dev = sysbus_create_simple("bcm2835_fb",
+        ARMCTRL_0_SBM_BASE + 0x400 + (MBOX_CHAN_FB<<4),
+        mbox_irq[MBOX_CHAN_FB]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_fb_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem,
+        BUS_ADDR(ARMCTRL_0_SBM_BASE + 0x400 + (MBOX_CHAN_FB<<4)),
+        per_fb_bus);
+
+    /* Property channel */
+    dev = sysbus_create_simple("bcm2835_property",
+        ARMCTRL_0_SBM_BASE + 0x400 + (MBOX_CHAN_PROPERTY<<4),
+        mbox_irq[MBOX_CHAN_PROPERTY]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_prop_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem,
+        BUS_ADDR(ARMCTRL_0_SBM_BASE + 0x400 + (MBOX_CHAN_PROPERTY<<4)),
+        per_prop_bus);
+
+    /* VCHIQ */
+    dev = sysbus_create_simple("bcm2835_vchiq",
+        ARMCTRL_0_SBM_BASE + 0x400 + (MBOX_CHAN_VCHIQ<<4),
+        mbox_irq[MBOX_CHAN_VCHIQ]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_vchiq_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem,
+        BUS_ADDR(ARMCTRL_0_SBM_BASE + 0x400 + (MBOX_CHAN_VCHIQ<<4)),
+        per_vchiq_bus);
+
+    /* Extended Mass Media Controller */
+    dev = sysbus_create_simple("bcm2835_emmc", EMMC_BASE,
+        pic[INTERRUPT_VC_ARASANSDIO]);
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_emmc_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(EMMC_BASE),
+        per_emmc_bus);
+
+    /* DMA Channels */
+    dev = qdev_create(NULL, "bcm2835_dma");
+    s = SYS_BUS_DEVICE(dev);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(s, 0, DMA_BASE);
+    sysbus_mmio_map(s, 1, (BCM2708_PERI_BASE + 0xe05000));
+    s = SYS_BUS_DEVICE(dev);
+    mr = sysbus_mmio_get_region(s, 0);
+    memory_region_init_alias(per_dma1_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(DMA_BASE),
+        per_dma1_bus);
+    mr = sysbus_mmio_get_region(s, 1);
+    memory_region_init_alias(per_dma2_bus, NULL, NULL, mr,
+        0, memory_region_size(mr));
+    memory_region_add_subregion(sysmem, BUS_ADDR(BCM2708_PERI_BASE + 0xe05000),
+        per_dma2_bus);
+    sysbus_connect_irq(s, 0, pic[INTERRUPT_DMA0]);
+    sysbus_connect_irq(s, 1, pic[INTERRUPT_DMA1]);
+    sysbus_connect_irq(s, 2, pic[INTERRUPT_VC_DMA2]);
+    sysbus_connect_irq(s, 3, pic[INTERRUPT_VC_DMA3]);
+    sysbus_connect_irq(s, 4, pic[INTERRUPT_DMA4]);
+    sysbus_connect_irq(s, 5, pic[INTERRUPT_DMA5]);
+    sysbus_connect_irq(s, 6, pic[INTERRUPT_DMA6]);
+    sysbus_connect_irq(s, 7, pic[INTERRUPT_DMA7]);
+    sysbus_connect_irq(s, 8, pic[INTERRUPT_DMA8]);
+    sysbus_connect_irq(s, 9, pic[INTERRUPT_DMA9]);
+    sysbus_connect_irq(s, 10, pic[INTERRUPT_DMA10]);
+    sysbus_connect_irq(s, 11, pic[INTERRUPT_DMA11]);
+    sysbus_connect_irq(s, 12, pic[INTERRUPT_DMA12]);
+
+    /* Finally, the board itself */
+    raspi_binfo.ram_size = bcm2835_vcram_base;
+    raspi_binfo.kernel_filename = args->kernel_filename;
+    raspi_binfo.kernel_cmdline = args->kernel_cmdline;
+    raspi_binfo.initrd_filename = args->initrd_filename;
+    raspi_binfo.board_id = 0xc42;
+
+    /* Quick and dirty "selector" */
+    if (args->initrd_filename
+        && !strcmp(args->kernel_filename, args->initrd_filename)) {
+
+        for (n = 0; n < ARRAY_SIZE(bootloader_0); n++) {
+            stl_phys((n << 2), bootloader_0[n]);
+        }
+        for (n = 0; n < ARRAY_SIZE(bootloader_100); n++) {
+            stl_phys(0x100 + (n << 2), bootloader_100[n]);
+        }
+        load_image_targphys(args->initrd_filename,
+                            0x8000,
+                            bcm2835_vcram_base - 0x8000);
+        cpu_reset(CPU(cpu));
+    } else {
+        arm_load_kernel(cpu, &raspi_binfo);
+    }
+}
+
+static QEMUMachine raspi_machine = {
+    .name = "raspi",
+    .desc = "Raspberry Pi",
+    .init = raspi_init
+};
+
+static void raspi_machine_init(void)
+{
+    qemu_register_machine(&raspi_machine);
+}
+
+machine_init(raspi_machine_init);
-- 
1.7.9.5


reply via email to

[Prev in Thread] Current Thread [Next in Thread]