diff mbox

[v9,4/4] xilinx_zynq: machine model initial version

Message ID b6d750d19fa2d2bcf4ac3a608ad37431e3cee987.1330921815.git.peter.crosthwaite@petalogix.com
State New
Headers show

Commit Message

Peter A. G. Crosthwaite March 5, 2012, 4:39 a.m. UTC
Xilinx zynq-7000 machine model. Also includes device model for the zynq-specific
system level control register (SLCR) module.

Signed-off-by: Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
Acked-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
---
changed from v8:
implemented vmsd for slcr
changed from v7:
removed (non-functional) SMP support
removed pflash #ifery
renamed zynq_arm_sysctl -> zynq_slcr
deleted bogus cryptic comments
marked slcr vmsd as unmigratable
CamelCased typedef enum types
changed from v6:
renamed qemu_debug() -> DB_PRINT
changed from v5:
removed usages of arm_boot_info->bootsmp_priv_base
changed from v4:
fixed FSF addess
changed device_init -> type_init
changes since v2:
removed 2 compile warnings from zynq_arm_sysctl.c
changes since v1:
Added gem init function
remowed WDT instantiation
Added maintainers information
removed dead sys_id and proc_id variables

 MAINTAINERS      |    7 +
 Makefile.target  |    1 +
 hw/xilinx_zynq.c |  157 ++++++++++++++++
 hw/zynq_slcr.c   |  535 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 700 insertions(+), 0 deletions(-)
 create mode 100644 hw/xilinx_zynq.c
 create mode 100644 hw/zynq_slcr.c

Comments

Anthony Liguori March 8, 2012, 4:42 p.m. UTC | #1
On 03/04/2012 10:39 PM, Peter A. G. Crosthwaite wrote:
> Xilinx zynq-7000 machine model. Also includes device model for the zynq-specific
> system level control register (SLCR) module.
>
> Signed-off-by: Peter A. G. Crosthwaite<peter.crosthwaite@petalogix.com>
> Acked-by: Edgar E. Iglesias<edgar.iglesias@gmail.com>

This breaks the build for me:

cc1: warnings being treated as errors
/home/anthony/git/qemu/hw/zynq_slcr.c: In function ‘zynq_slcr_read’:
/home/anthony/git/qemu/hw/zynq_slcr.c:314:25: error: array subscript is above 
array bounds
/home/anthony/git/qemu/hw/zynq_slcr.c: In function ‘zynq_slcr_write’:
/home/anthony/git/qemu/hw/zynq_slcr.c:457:22: error: array subscript is above 
array bounds
make[1]: *** [zynq_slcr.o] Error 1


> +        case 0xA60 ... 0xA8C:
> +            s->afi[0][(offset - 0x700) / 4] = val;
> +            break;

And GCC is definitely right here.  This will pretty clearly overflow the array 
if offset is any of the allowable values per the switch statement.

Regards,

Anthony Liguori
Peter A. G. Crosthwaite March 10, 2012, 10:15 a.m. UTC | #2
On it

On Fri, Mar 9, 2012 at 2:42 AM, Anthony Liguori <anthony@codemonkey.ws> wrote:
> On 03/04/2012 10:39 PM, Peter A. G. Crosthwaite wrote:
>>
>> Xilinx zynq-7000 machine model. Also includes device model for the
>> zynq-specific
>> system level control register (SLCR) module.
>>
>> Signed-off-by: Peter A. G. Crosthwaite<peter.crosthwaite@petalogix.com>
>> Acked-by: Edgar E. Iglesias<edgar.iglesias@gmail.com>
>
>
> This breaks the build for me:
>
> cc1: warnings being treated as errors
> /home/anthony/git/qemu/hw/zynq_slcr.c: In function ‘zynq_slcr_read’:
> /home/anthony/git/qemu/hw/zynq_slcr.c:314:25: error: array subscript is
> above array bounds
> /home/anthony/git/qemu/hw/zynq_slcr.c: In function ‘zynq_slcr_write’:
> /home/anthony/git/qemu/hw/zynq_slcr.c:457:22: error: array subscript is
> above array bounds
> make[1]: *** [zynq_slcr.o] Error 1
>
>
>
>> +        case 0xA60 ... 0xA8C:
>> +            s->afi[0][(offset - 0x700) / 4] = val;
>> +            break;
>
>
> And GCC is definitely right here.  This will pretty clearly overflow the
> array if offset is any of the allowable values per the switch statement.
>
> Regards,
>
> Anthony Liguori
Peter A. G. Crosthwaite March 10, 2012, 10:22 a.m. UTC | #3
nvm,

youve got it covered. Thanks Anthony.

On Sat, Mar 10, 2012 at 8:15 PM, Peter Crosthwaite
<peter.crosthwaite@petalogix.com> wrote:
> On it
>
> On Fri, Mar 9, 2012 at 2:42 AM, Anthony Liguori <anthony@codemonkey.ws> wrote:
>> On 03/04/2012 10:39 PM, Peter A. G. Crosthwaite wrote:
>>>
>>> Xilinx zynq-7000 machine model. Also includes device model for the
>>> zynq-specific
>>> system level control register (SLCR) module.
>>>
>>> Signed-off-by: Peter A. G. Crosthwaite<peter.crosthwaite@petalogix.com>
>>> Acked-by: Edgar E. Iglesias<edgar.iglesias@gmail.com>
>>
>>
>> This breaks the build for me:
>>
>> cc1: warnings being treated as errors
>> /home/anthony/git/qemu/hw/zynq_slcr.c: In function ‘zynq_slcr_read’:
>> /home/anthony/git/qemu/hw/zynq_slcr.c:314:25: error: array subscript is
>> above array bounds
>> /home/anthony/git/qemu/hw/zynq_slcr.c: In function ‘zynq_slcr_write’:
>> /home/anthony/git/qemu/hw/zynq_slcr.c:457:22: error: array subscript is
>> above array bounds
>> make[1]: *** [zynq_slcr.o] Error 1
>>
>>
>>
>>> +        case 0xA60 ... 0xA8C:
>>> +            s->afi[0][(offset - 0x700) / 4] = val;
>>> +            break;
>>
>>
>> And GCC is definitely right here.  This will pretty clearly overflow the
>> array if offset is any of the allowable values per the switch statement.
>>
>> Regards,
>>
>> Anthony Liguori
diff mbox

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 0b3b3d8..d249947 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -251,6 +251,13 @@  M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: hw/versatilepb.c
 
+Xilinx Zynq
+M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
+S: Maintained
+F: hw/xilinx_zynq.c
+F: hw/zynq_slcr.c
+F: hw/cadence_*
+
 CRIS Machines
 -------------
 Axis Dev88
diff --git a/Makefile.target b/Makefile.target
index 8afb34c..891d5d1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -348,6 +348,7 @@  obj-arm-y += versatile_pci.o
 obj-arm-y += cadence_uart.o
 obj-arm-y += cadence_ttc.o
 obj-arm-y += cadence_gem.o
+obj-arm-y += xilinx_zynq.o zynq_slcr.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
 obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c
new file mode 100644
index 0000000..ea13e8c
--- /dev/null
+++ b/hw/xilinx_zynq.c
@@ -0,0 +1,157 @@ 
+/*
+ * Xilinx Zynq Baseboard System emulation.
+ *
+ * Copyright (c) 2010 Xilinx.
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com)
+ * Copyright (c) 2012 Petalogix Pty Ltd.
+ * Written by Haibing Ma
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "net.h"
+#include "exec-memory.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "flash.h"
+#include "blockdev.h"
+#include "loader.h"
+
+#define FLASH_SIZE (64 * 1024 * 1024)
+#define FLASH_SECTOR_SIZE (128 * 1024)
+
+#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
+
+static struct arm_boot_info zynq_binfo = {};
+
+static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    qemu_check_nic_model(nd, "cadence_gem");
+    dev = qdev_create(NULL, "cadence_gem");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, base);
+    sysbus_connect_irq(s, 0, irq);
+}
+
+static void zynq_init(ram_addr_t ram_size, const char *boot_device,
+                        const char *kernel_filename, const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env = NULL;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
+    MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
+    DeviceState *dev;
+    SysBusDevice *busdev;
+    qemu_irq *irqp;
+    qemu_irq pic[64];
+    NICInfo *nd;
+    int n;
+    qemu_irq cpu_irq;
+
+    if (!cpu_model) {
+        cpu_model = "cortex-a9";
+    }
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    irqp = arm_pic_init_cpu(env);
+    cpu_irq = irqp[ARM_PIC_CPU_IRQ];
+
+    /* max 2GB ram */
+    if (ram_size > 0x80000000) {
+        ram_size = 0x80000000;
+    }
+
+    /* DDR remapped to address zero.  */
+    memory_region_init_ram(ext_ram, "zynq.ext_ram", ram_size);
+    vmstate_register_ram_global(ext_ram);
+    memory_region_add_subregion(address_space_mem, 0, ext_ram);
+
+    /* 256K of on-chip memory */
+    memory_region_init_ram(ocm_ram, "zynq.ocm_ram", 256 << 10);
+    vmstate_register_ram_global(ocm_ram);
+    memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
+
+    DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
+
+    /* AMD */
+    pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE,
+                          dinfo ? dinfo->bdrv : NULL, FLASH_SECTOR_SIZE,
+                          FLASH_SIZE/FLASH_SECTOR_SIZE, 1,
+                          1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa,
+                              0);
+
+    dev = qdev_create(NULL, "xilinx,zynq_slcr");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xF8000000);
+
+    dev = qdev_create(NULL, "a9mpcore_priv");
+    qdev_prop_set_uint32(dev, "num-cpu", 1);
+    qdev_init_nofail(dev);
+    busdev = sysbus_from_qdev(dev);
+    sysbus_mmio_map(busdev, 0, 0xF8F00000);
+    sysbus_connect_irq(busdev, 0, cpu_irq);
+
+    for (n = 0; n < 64; n++) {
+        pic[n] = qdev_get_gpio_in(dev, n);
+    }
+
+    sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]);
+    sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]);
+
+    sysbus_create_varargs("cadence_ttc", 0xF8001000,
+            pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL);
+    sysbus_create_varargs("cadence_ttc", 0xF8002000,
+            pic[69-IRQ_OFFSET], pic[70-IRQ_OFFSET], pic[71-IRQ_OFFSET], NULL);
+
+    for (n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+        if (n == 0) {
+            gem_init(nd, 0xE000B000, pic[54-IRQ_OFFSET]);
+        } else if (n == 1) {
+            gem_init(nd, 0xE000C000, pic[77-IRQ_OFFSET]);
+        }
+    }
+
+    zynq_binfo.ram_size = ram_size;
+    zynq_binfo.kernel_filename = kernel_filename;
+    zynq_binfo.kernel_cmdline = kernel_cmdline;
+    zynq_binfo.initrd_filename = initrd_filename;
+    zynq_binfo.nb_cpus = 1;
+    zynq_binfo.board_id = 0xd32;
+    zynq_binfo.loader_start = 0;
+    arm_load_kernel(first_cpu, &zynq_binfo);
+}
+
+static QEMUMachine zynq_machine = {
+    .name = "xilinx-zynq-a9",
+    .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9",
+    .init = zynq_init,
+    .use_scsi = 1,
+    .max_cpus = 1,
+    .no_sdcard = 1
+};
+
+static void zynq_machine_init(void)
+{
+    qemu_register_machine(&zynq_machine);
+}
+
+machine_init(zynq_machine_init);
diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c
new file mode 100644
index 0000000..b785f04
--- /dev/null
+++ b/hw/zynq_slcr.c
@@ -0,0 +1,535 @@ 
+/*
+ * Status and system control registers for Xilinx Zynq Platform
+ *
+ * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (c) 2012 PetaLogix Pty Ltd.
+ * Based on hw/arm_sysctl.c, written by Paul Brook
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "sysbus.h"
+#include "sysemu.h"
+
+#ifdef ZYNQ_ARM_SLCR_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+#define XILINX_LOCK_KEY 0x767b
+#define XILINX_UNLOCK_KEY 0xdf0d
+
+typedef enum {
+  ARM_PLL_CTRL,
+  DDR_PLL_CTRL,
+  IO_PLL_CTRL,
+  PLL_STATUS,
+  ARM_PPL_CFG,
+  DDR_PLL_CFG,
+  IO_PLL_CFG,
+  PLL_BG_CTRL,
+  PLL_MAX
+} PLLValues;
+
+typedef enum {
+  ARM_CLK_CTRL,
+  DDR_CLK_CTRL,
+  DCI_CLK_CTRL,
+  APER_CLK_CTRL,
+  USB0_CLK_CTRL,
+  USB1_CLK_CTRL,
+  GEM0_RCLK_CTRL,
+  GEM1_RCLK_CTRL,
+  GEM0_CLK_CTRL,
+  GEM1_CLK_CTRL,
+  SMC_CLK_CTRL,
+  LQSPI_CLK_CTRL,
+  SDIO_CLK_CTRL,
+  UART_CLK_CTRL,
+  SPI_CLK_CTRL,
+  CAN_CLK_CTRL,
+  CAN_MIOCLK_CTRL,
+  DBG_CLK_CTRL,
+  PCAP_CLK_CTRL,
+  TOPSW_CLK_CTRL,
+  CLK_MAX
+} ClkValues;
+
+typedef enum {
+  CLK_CTRL,
+  THR_CTRL,
+  THR_CNT,
+  THR_STA,
+  FPGA_MAX
+} FPGAValues;
+
+typedef enum {
+  SYNC_CTRL,
+  SYNC_STATUS,
+  BANDGAP_TRIP,
+  CC_TEST,
+  PLL_PREDIVISOR,
+  CLK_621_TRUE,
+  PICTURE_DBG,
+  PICTURE_DBG_UCNT,
+  PICTURE_DBG_LCNT,
+  MISC_MAX
+} MiscValues;
+
+typedef enum {
+  PSS,
+  DDDR,
+  DMAC,
+  USB,
+  GEM,
+  SDIO,
+  SPI,
+  CAN,
+  I2C,
+  UART,
+  GPIO,
+  LQSPI,
+  SMC,
+  OCM,
+  DEVCI,
+  FPGA,
+  A9_CPU,
+  RS_AWDT,
+  RST_REASON,
+  RST_REASON_CLR,
+  REBOOT_STATUS,
+  BOOT_MODE,
+  RESET_MAX
+} ResetValues;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    union {
+        struct {
+            uint16_t scl;
+            uint16_t lockval;
+            uint32_t pll[PLL_MAX]; /* 0x100 - 0x11C */
+            uint32_t clk[CLK_MAX]; /* 0x120 - 0x16C */
+            uint32_t fpga[4][FPGA_MAX]; /* 0x170 - 0x1AC */
+            uint32_t misc[MISC_MAX]; /* 0x1B0 - 0x1D8 */
+            uint32_t reset[RESET_MAX]; /* 0x200 - 0x25C */
+            uint32_t apu_ctrl; /* 0x300 */
+            uint32_t wdt_clk_sel; /* 0x304 */
+            uint32_t tz_ocm[3]; /* 0x400 - 0x408 */
+            uint32_t tz_ddr; /* 0x430 */
+            uint32_t tz_dma[3]; /* 0x440 - 0x448 */
+            uint32_t tz_misc[3]; /* 0x450 - 0x458 */
+            uint32_t tz_fpga[2]; /* 0x484 - 0x488 */
+            uint32_t dbg_ctrl; /* 0x500 */
+            uint32_t pss_idcode; /* 0x530 */
+            uint32_t ddr[8]; /* 0x600 - 0x620 - 0x604-missing */
+            uint32_t mio[54]; /* 0x700 - 0x7D4 */
+            uint32_t mio_func[4]; /* 0x800 - 0x810 */
+            uint32_t sd[2]; /* 0x830 - 0x834 */
+            uint32_t lvl_shftr_en; /* 0x900 */
+            uint32_t ocm_cfg; /* 0x910 */
+            uint32_t cpu_ram[8]; /* 0xA00 - 0xA1C */
+            uint32_t iou[7]; /* 0xA30 - 0xA48 */
+            uint32_t dmac_ram; /* 0xA50 */
+            uint32_t afi[4][3]; /* 0xA60 - 0xA8C */
+            uint32_t ocm[3]; /* 0xA90 - 0xA98 */
+            uint32_t devci_ram; /* 0xAA0 */
+            uint32_t csg_ram; /* 0xAB0 */
+            uint32_t gpiob[12]; /* 0xB00 - 0xB2C */
+            uint32_t ddriob[14]; /* 0xB40 - 0xB74 */
+        };
+        uint8_t data[0x1000];
+    };
+} ZynqSLCRState;
+
+static void zynq_slcr_reset(DeviceState *d)
+{
+    int i;
+    ZynqSLCRState *s =
+            FROM_SYSBUS(ZynqSLCRState, sysbus_from_qdev(d));
+
+    DB_PRINT("RESET\n");
+
+    s->lockval = 1;
+    /* 0x100 - 0x11C */
+    s->pll[ARM_PLL_CTRL] = 0x0001A008;
+    s->pll[DDR_PLL_CTRL] = 0x0001A008;
+    s->pll[IO_PLL_CTRL] = 0x0001A008;
+    s->pll[PLL_STATUS] = 0x0000003F;
+    s->pll[ARM_PPL_CFG] = 0x00014000;
+    s->pll[DDR_PLL_CFG] = 0x00014000;
+    s->pll[IO_PLL_CFG] = 0x00014000;
+
+    /* 0x120 - 0x16C */
+    s->clk[ARM_CLK_CTRL] = 0x1F000400;
+    s->clk[DDR_CLK_CTRL] = 0x18400003;
+    s->clk[DCI_CLK_CTRL] = 0x01E03201;
+    s->clk[APER_CLK_CTRL] = 0x01FFCCCD;
+    s->clk[USB0_CLK_CTRL] = s->clk[USB1_CLK_CTRL] = 0x00101941;
+    s->clk[GEM0_RCLK_CTRL] = s->clk[GEM1_RCLK_CTRL] = 0x00000001;
+    s->clk[GEM0_CLK_CTRL] = s->clk[GEM1_CLK_CTRL] = 0x00003C01;
+    s->clk[SMC_CLK_CTRL] = 0x00003C01;
+    s->clk[LQSPI_CLK_CTRL] = 0x00002821;
+    s->clk[SDIO_CLK_CTRL] = 0x00001E03;
+    s->clk[UART_CLK_CTRL] = 0x00003F03;
+    s->clk[SPI_CLK_CTRL] = 0x00003F03;
+    s->clk[CAN_CLK_CTRL] = 0x00501903;
+    s->clk[DBG_CLK_CTRL] = 0x00000F03;
+    s->clk[PCAP_CLK_CTRL] = 0x00000F01;
+
+    /* 0x170 - 0x1AC */
+    s->fpga[0][CLK_CTRL] = s->fpga[1][CLK_CTRL] = s->fpga[2][CLK_CTRL] =
+            s->fpga[3][CLK_CTRL] = 0x00101800;
+    s->fpga[0][THR_STA] = s->fpga[1][THR_STA] = s->fpga[2][THR_STA] =
+            s->fpga[3][THR_STA] = 0x00010000;
+
+    /* 0x1B0 - 0x1D8 */
+    s->misc[BANDGAP_TRIP] = 0x0000001F;
+    s->misc[PLL_PREDIVISOR] = 0x00000001;
+    s->misc[CLK_621_TRUE] = 0x00000001;
+
+    /* 0x200 - 0x25C */
+    s->reset[FPGA] = 0x01F33F0F;
+    s->reset[RST_REASON] = 0x00000040;
+
+    /* 0x700 - 0x7D4 */
+    for (i = 0; i < 54; i++) {
+        s->mio[i] = 0x00001601;
+    }
+    for (i = 2; i <= 8; i++) {
+        s->mio[i] = 0x00000601;
+    }
+
+    /* MIO_MST_TRI0, MIO_MST_TRI1 */
+    s->mio_func[2] = s->mio_func[3] = 0xFFFFFFFF;
+
+    s->cpu_ram[0] = s->cpu_ram[1] = s->cpu_ram[3] =
+            s->cpu_ram[4] = s->cpu_ram[7] = 0x00010101;
+    s->cpu_ram[2] = s->cpu_ram[5] = 0x01010101;
+    s->cpu_ram[6] = 0x00000001;
+
+    s->iou[0] = s->iou[1] = s->iou[2] = s->iou[3] = 0x09090909;
+    s->iou[4] = s->iou[5] = 0x00090909;
+    s->iou[6] = 0x00000909;
+
+    s->dmac_ram = 0x00000009;
+
+    s->afi[0][0] = s->afi[0][1] = 0x09090909;
+    s->afi[1][0] = s->afi[1][1] = 0x09090909;
+    s->afi[2][0] = s->afi[2][1] = 0x09090909;
+    s->afi[3][0] = s->afi[3][1] = 0x09090909;
+    s->afi[0][2] = s->afi[1][2] = s->afi[2][2] = s->afi[3][2] = 0x00000909;
+
+    s->ocm[0] = 0x01010101;
+    s->ocm[1] = s->ocm[2] = 0x09090909;
+
+    s->devci_ram = 0x00000909;
+    s->csg_ram = 0x00000001;
+
+    s->ddriob[0] = s->ddriob[1] = s->ddriob[2] = s->ddriob[3] = 0x00000e00;
+    s->ddriob[4] = s->ddriob[5] = s->ddriob[6] = 0x00000e00;
+    s->ddriob[12] = 0x00000021;
+}
+
+static inline uint32_t zynq_slcr_read_imp(void *opaque,
+    target_phys_addr_t offset)
+{
+    ZynqSLCRState *s = (ZynqSLCRState *)opaque;
+
+    switch (offset) {
+    case 0x0: /* SCL */
+        return s->scl;
+    case 0x4: /* LOCK */
+    case 0x8: /* UNLOCK */
+        DB_PRINT("Reading SCLR_LOCK/UNLOCK is not enabled\n");
+        return 0;
+    case 0x0C: /* LOCKSTA */
+        return s->lockval;
+    case 0x100 ... 0x11C:
+        return s->pll[(offset - 0x100) / 4];
+    case 0x120 ... 0x16C:
+        return s->clk[(offset - 0x120) / 4];
+    case 0x170 ... 0x1AC:
+        return s->fpga[0][(offset - 0x170) / 4];
+    case 0x1B0 ... 0x1D8:
+        return s->misc[(offset - 0x1B0) / 4];
+    case 0x200 ... 0x258:
+        return s->reset[(offset - 0x200) / 4];
+    case 0x25c:
+        return 1;
+    case 0x300:
+        return s->apu_ctrl;
+    case 0x304:
+        return s->wdt_clk_sel;
+    case 0x400 ... 0x408:
+        return s->tz_ocm[(offset - 0x400) / 4];
+    case 0x430:
+        return s->tz_ddr;
+    case 0x440 ... 0x448:
+        return s->tz_dma[(offset - 0x440) / 4];
+    case 0x450 ... 0x458:
+        return s->tz_misc[(offset - 0x450) / 4];
+    case 0x484 ... 0x488:
+        return s->tz_fpga[(offset - 0x484) / 4];
+    case 0x500:
+        return s->dbg_ctrl;
+    case 0x530:
+        return s->pss_idcode;
+    case 0x600 ... 0x620:
+        if (offset == 0x604) {
+            goto bad_reg;
+        }
+        return s->ddr[(offset - 0x600) / 4];
+    case 0x700 ... 0x7D4:
+        return s->mio[(offset - 0x700) / 4];
+    case 0x800 ... 0x810:
+        return s->mio_func[(offset - 0x800) / 4];
+    case 0x830 ... 0x834:
+        return s->sd[(offset - 0x830) / 4];
+    case 0x900:
+        return s->lvl_shftr_en;
+    case 0x910:
+        return s->ocm_cfg;
+    case 0xA00 ... 0xA1C:
+        return s->cpu_ram[(offset - 0xA00) / 4];
+    case 0xA30 ... 0xA48:
+        return s->iou[(offset - 0xA30) / 4];
+    case 0xA50:
+        return s->dmac_ram;
+    case 0xA60 ... 0xA8C:
+        return s->afi[0][(offset - 0x700) / 4];
+    case 0xA90 ... 0xA98:
+        return s->ocm[(offset - 0xA90) / 4];
+    case 0xAA0:
+        return s->devci_ram;
+    case 0xAB0:
+        return s->csg_ram;
+    case 0xB00 ... 0xB2C:
+        return s->gpiob[(offset - 0xB00) / 4];
+    case 0xB40 ... 0xB74:
+        return s->ddriob[(offset - 0xB40) / 4];
+    default:
+    bad_reg:
+        DB_PRINT("Bad register offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static uint64_t zynq_slcr_read(void *opaque, target_phys_addr_t offset,
+    unsigned size)
+{
+    uint32_t ret = zynq_slcr_read_imp(opaque, offset);
+
+    DB_PRINT("addr: %08x data: %08x\n", offset, ret);
+    return ret;
+}
+
+static void zynq_slcr_write(void *opaque, target_phys_addr_t offset,
+                          uint64_t val, unsigned size)
+{
+    ZynqSLCRState *s = (ZynqSLCRState *)opaque;
+
+    DB_PRINT("offset: %08x data: %08x\n", offset, (unsigned)val);
+
+    switch (offset) {
+    case 0x00: /* SCL */
+        s->scl = val & 0x1;
+    return;
+    case 0x4: /* SLCR_LOCK */
+        if ((val & 0xFFFF) == XILINX_LOCK_KEY) {
+            DB_PRINT("XILINX LOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
+                (unsigned)val & 0xFFFF);
+            s->lockval = 1;
+        } else {
+            DB_PRINT("WRONG XILINX LOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
+                (int)offset, (unsigned)val & 0xFFFF);
+        }
+        return;
+    case 0x8: /* SLCR_UNLOCK */
+        if ((val & 0xFFFF) == XILINX_UNLOCK_KEY) {
+            DB_PRINT("XILINX UNLOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
+                (unsigned)val & 0xFFFF);
+            s->lockval = 0;
+        } else {
+            DB_PRINT("WRONG XILINX UNLOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
+                (int)offset, (unsigned)val & 0xFFFF);
+        }
+        return;
+    case 0xc: /* LOCKSTA */
+        DB_PRINT("Writing SCLR_LOCKSTA is not enabled\n");
+        return;
+    }
+
+    if (!s->lockval) {
+        switch (offset) {
+        case 0x100 ... 0x11C:
+            if (offset == 0x10C) {
+                goto bad_reg;
+            }
+            s->pll[(offset - 0x100) / 4] = val;
+            break;
+        case 0x120 ... 0x16C:
+            s->clk[(offset - 0x120) / 4] = val;
+            break;
+        case 0x170 ... 0x1AC:
+            s->fpga[0][(offset - 0x170) / 4] = val;
+            break;
+        case 0x1B0 ... 0x1D8:
+            s->misc[(offset - 0x1B0) / 4] = val;
+            break;
+        case 0x200 ... 0x25C:
+            if (offset == 0x250) {
+                goto bad_reg;
+            }
+            s->reset[(offset - 0x200) / 4] = val;
+            break;
+        case 0x300:
+            s->apu_ctrl = val;
+            break;
+        case 0x304:
+            s->wdt_clk_sel = val;
+            break;
+        case 0x400 ... 0x408:
+            s->tz_ocm[(offset - 0x400) / 4] = val;
+            break;
+        case 0x430:
+            s->tz_ddr = val;
+            break;
+        case 0x440 ... 0x448:
+            s->tz_dma[(offset - 0x440) / 4] = val;
+            break;
+        case 0x450 ... 0x458:
+            s->tz_misc[(offset - 0x450) / 4] = val;
+            break;
+        case 0x484 ... 0x488:
+            s->tz_fpga[(offset - 0x484) / 4] = val;
+            break;
+        case 0x500:
+            s->dbg_ctrl = val;
+            break;
+        case 0x530:
+            s->pss_idcode = val;
+            break;
+        case 0x600 ... 0x620:
+            if (offset == 0x604) {
+                goto bad_reg;
+            }
+            s->ddr[(offset - 0x600) / 4] = val;
+            break;
+        case 0x700 ... 0x7D4:
+            s->mio[(offset - 0x700) / 4] = val;
+            break;
+        case 0x800 ... 0x810:
+            s->mio_func[(offset - 0x800) / 4] = val;
+            break;
+        case 0x830 ... 0x834:
+            s->sd[(offset - 0x830) / 4] = val;
+            break;
+        case 0x900:
+            s->lvl_shftr_en = val;
+            break;
+        case 0x910:
+            break;
+        case 0xA00 ... 0xA1C:
+            s->cpu_ram[(offset - 0xA00) / 4] = val;
+            break;
+        case 0xA30 ... 0xA48:
+            s->iou[(offset - 0xA30) / 4] = val;
+            break;
+        case 0xA50:
+            s->dmac_ram = val;
+            break;
+        case 0xA60 ... 0xA8C:
+            s->afi[0][(offset - 0x700) / 4] = val;
+            break;
+        case 0xA90:
+            s->ocm[0] = val;
+            break;
+        case 0xAA0:
+            s->devci_ram = val;
+            break;
+        case 0xAB0:
+            s->csg_ram = val;
+            break;
+        case 0xB00 ... 0xB2C:
+            if (offset == 0xB20 || offset == 0xB2C) {
+                goto bad_reg;
+            }
+            s->gpiob[(offset - 0xB00) / 4] = val;
+            break;
+        case 0xB40 ... 0xB74:
+            s->ddriob[(offset - 0xB40) / 4] = val;
+            break;
+        default:
+        bad_reg:
+            DB_PRINT("Bad register write %x <= %08x\n", (int)offset, val);
+        }
+    } else {
+        DB_PRINT("SCLR registers are locked. Unlock them first\n");
+    }
+}
+
+static const MemoryRegionOps slcr_ops = {
+    .read = zynq_slcr_read,
+    .write = zynq_slcr_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int zynq_slcr_init(SysBusDevice *dev)
+{
+    ZynqSLCRState *s = FROM_SYSBUS(ZynqSLCRState, dev);
+
+    memory_region_init_io(&s->iomem, &slcr_ops, s, "slcr", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_zynq_slcr = {
+    .name = "zynq_slcr",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(data, ZynqSLCRState, 0x1000),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void zynq_slcr_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = zynq_slcr_init;
+    dc->vmsd = &vmstate_zynq_slcr;
+    dc->reset = zynq_slcr_reset;
+}
+
+static TypeInfo zynq_slcr_info = {
+    .class_init = zynq_slcr_class_init,
+    .name  = "xilinx,zynq_slcr",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(ZynqSLCRState),
+};
+
+static void zynq_slcr_register_types(void)
+{
+    type_register_static(&zynq_slcr_info);
+}
+
+type_init(zynq_slcr_register_types)