All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] arm: Raspberry Pi support
@ 2013-12-02 11:11 Jan Petrouš
  2013-12-02 20:01 ` Stefan Weil
  2013-12-02 20:11 ` Peter Maydell
  0 siblings, 2 replies; 5+ messages in thread
From: Jan Petrouš @ 2013-12-02 11:11 UTC (permalink / raw)
  To: QEMU Developers, Grégory ESTRADE

[-- Attachment #1: Type: text/plain, Size: 210666 bytes --]

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

The code is (c) Gregory Estrade <gregory.estrade@gmail.com>
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 <jan.petrous@tieto.com>.

Signed-off-by: Gregory Estrade <gregory.estrade@gmail.com>
Signed-off-by: Jan Petrous <jan.petrous@tieto.com>
---
 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=%08x dst=%08x len=%08x\n", c,
+        ch->source_ad, ch->dest_ad, ch->txfr_len);
+#endif
+
+        while (ch->txfr_len != 0) {
+            data = 0;
+            if (ch->ti & (1 << 11)) {
+                /* Ignore reads */
+            } else {
+                data = ldl_phys(ch->source_ad);
+            }
+            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=%08x 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 = 0;
+        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 = value;
+
+        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 = 0;
+    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 <michael@walle.cc>
+ *
+ * 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:
+ *   http://www.milkymist.org/socdoc/vgafb.pdf
+ */
+
+#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;
+}
+
+/* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface*/
+
+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... */
+        /* see http://plan9.bell-labs.com/sources/contrib/ \
+         * 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

[-- Attachment #2: Type: text/html, Size: 291422 bytes --]

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH] arm: Raspberry Pi support
  2013-12-02 11:11 [Qemu-devel] [PATCH] arm: Raspberry Pi support Jan Petrouš
@ 2013-12-02 20:01 ` Stefan Weil
  2013-12-02 20:11   ` Gregory ESTRADE
  2013-12-02 20:11 ` Peter Maydell
  1 sibling, 1 reply; 5+ messages in thread
From: Stefan Weil @ 2013-12-02 20:01 UTC (permalink / raw)
  To: Jan Petrouš, QEMU Developers, Grégory ESTRADE

Am 02.12.2013 12:11, schrieb Jan Petrouš:
>
> Initial commit. Added 'raspi' virtual platform and corresponding
> BCM2835 devices support.
>
> The code is (c) Gregory Estrade <gregory.estrade@gmail.com
> <mailto:gregory.estrade@gmail.com>>
> 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 <jan.petrous@tieto.com
> <mailto:jan.petrous@tieto.com>>.
>
> Signed-off-by: Gregory Estrade <gregory.estrade@gmail.com
> <mailto:gregory.estrade@gmail.com>>
> Signed-off-by: Jan Petrous <jan.petrous@tieto.com
> <mailto:jan.petrous@tieto.com>>
>


Hi Jan,

please send your next e-mails in simple text instead of html format. If
you use "git send-email", it will be formatted in the right way.

The patch which you have send here is not the latest version from
Grégory. Comments for this patch are nevertheless welcome. I have
included the system emulation for Raspberry Pi in my personal git tree
since several months now and would be delighted to see it as part of the
official QEMU code.

Regards,
Stefan Weil

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH] arm: Raspberry Pi support
  2013-12-02 20:01 ` Stefan Weil
@ 2013-12-02 20:11   ` Gregory ESTRADE
  0 siblings, 0 replies; 5+ messages in thread
From: Gregory ESTRADE @ 2013-12-02 20:11 UTC (permalink / raw)
  To: Stefan Weil, Jan Petrouš, QEMU Developers

Hi Jan, Stefan and all people at the qemu-devel  mailing list :)
As Stefan stated, there's a new patch in progress, which includes 
additional cleanup.
Sorry Jan, I should have notified you about it before.
However, I would love to see any comments about it.

Regards,
Greg

Le 02/12/2013 21:01, Stefan Weil a écrit :
> Am 02.12.2013 12:11, schrieb Jan Petrouš:
>> Initial commit. Added 'raspi' virtual platform and corresponding
>> BCM2835 devices support.
>>
>> The code is (c) Gregory Estrade <gregory.estrade@gmail.com
>> <mailto:gregory.estrade@gmail.com>>
>> 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 <jan.petrous@tieto.com
>> <mailto:jan.petrous@tieto.com>>.
>>
>> Signed-off-by: Gregory Estrade <gregory.estrade@gmail.com
>> <mailto:gregory.estrade@gmail.com>>
>> Signed-off-by: Jan Petrous <jan.petrous@tieto.com
>> <mailto:jan.petrous@tieto.com>>
>>
>
> Hi Jan,
>
> please send your next e-mails in simple text instead of html format. If
> you use "git send-email", it will be formatted in the right way.
>
> The patch which you have send here is not the latest version from
> Grégory. Comments for this patch are nevertheless welcome. I have
> included the system emulation for Raspberry Pi in my personal git tree
> since several months now and would be delighted to see it as part of the
> official QEMU code.
>
> Regards,
> Stefan Weil
>
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH] arm: Raspberry Pi support
  2013-12-02 11:11 [Qemu-devel] [PATCH] arm: Raspberry Pi support Jan Petrouš
  2013-12-02 20:01 ` Stefan Weil
@ 2013-12-02 20:11 ` Peter Maydell
  2013-12-03 10:10   ` Jan Petrouš
  1 sibling, 1 reply; 5+ messages in thread
From: Peter Maydell @ 2013-12-02 20:11 UTC (permalink / raw)
  To: Jan Petrouš; +Cc: QEMU Developers, Grégory ESTRADE

On 2 December 2013 11:11, Jan Petrouš <jan.petrous@tieto.com> wrote:
>
> Initial commit. Added 'raspi' virtual platform and corresponding
> BCM2835 devices support.
>
> The code is (c) Gregory Estrade <gregory.estrade@gmail.com>
> 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 <jan.petrous@tieto.com>.
>
> Signed-off-by: Gregory Estrade <gregory.estrade@gmail.com>
> Signed-off-by: Jan Petrous <jan.petrous@tieto.com>
> ---
>  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(+)

Hi. Thanks for this patch -- I'm sure there are a lot of people who'd
like to see raspberry pi emulation in upstream. However, I'm afraid
this patch is not reviewable in this format. You really need to break
it up into a series of smaller patches each of which add one device
or similarly sized feature.

You might like to read http://wiki.qemu.org/Contribute/SubmitAPatch
if you haven't already for some other information on how our
patch review process works. I'd also strongly recommend you browse
the list archives to look at what has been said about some other
recent series supplying ARM board support (like the sunxi and
DIGIC board patch series) -- review comments made in those email
threads about patch series structure, where source files should go
in the directory tree, how to model SoCs, etc are very likely to
apply to your series too.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH] arm: Raspberry Pi support
  2013-12-02 20:11 ` Peter Maydell
@ 2013-12-03 10:10   ` Jan Petrouš
  0 siblings, 0 replies; 5+ messages in thread
From: Jan Petrouš @ 2013-12-03 10:10 UTC (permalink / raw)
  To: Peter Maydell; +Cc: QEMU Developers, Grégory ESTRADE

[-- Attachment #1: Type: text/plain, Size: 288 bytes --]

Sorry guys for html, I didn't know that my company's mail has such default
formatting :(

I was on bussiness trip for few days so replaying only now.
And as Greg said, it looks like we have another progress on raspi machine
so I will check that and return back soon, hopefully ;)

/Jan



[-- Attachment #2: Type: text/html, Size: 401 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-12-03 10:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-02 11:11 [Qemu-devel] [PATCH] arm: Raspberry Pi support Jan Petrouš
2013-12-02 20:01 ` Stefan Weil
2013-12-02 20:11   ` Gregory ESTRADE
2013-12-02 20:11 ` Peter Maydell
2013-12-03 10:10   ` Jan Petrouš

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.