summaryrefslogtreecommitdiffstats
path: root/qemu/hw/arm/xilinx_zynq.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/hw/arm/xilinx_zynq.c')
-rw-r--r--qemu/hw/arm/xilinx_zynq.c120
1 files changed, 83 insertions, 37 deletions
diff --git a/qemu/hw/arm/xilinx_zynq.c b/qemu/hw/arm/xilinx_zynq.c
index a4e7b5c63..98b17c9ae 100644
--- a/qemu/hw/arm/xilinx_zynq.c
+++ b/qemu/hw/arm/xilinx_zynq.c
@@ -15,6 +15,10 @@
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "cpu.h"
#include "hw/sysbus.h"
#include "hw/arm/arm.h"
#include "net/net.h"
@@ -24,8 +28,10 @@
#include "hw/block/flash.h"
#include "sysemu/block-backend.h"
#include "hw/loader.h"
-#include "hw/ssi.h"
+#include "hw/misc/zynq-xadc.h"
+#include "hw/ssi/ssi.h"
#include "qemu/error-report.h"
+#include "hw/sd/sd.h"
#define NUM_SPI_FLASHES 4
#define NUM_QSPI_FLASHES 2
@@ -43,6 +49,45 @@ static const int dma_irqs[8] = {
46, 47, 48, 49, 72, 73, 74, 75
};
+#define BOARD_SETUP_ADDR 0x100
+
+#define SLCR_LOCK_OFFSET 0x004
+#define SLCR_UNLOCK_OFFSET 0x008
+#define SLCR_ARM_PLL_OFFSET 0x100
+
+#define SLCR_XILINX_UNLOCK_KEY 0xdf0d
+#define SLCR_XILINX_LOCK_KEY 0x767b
+
+#define ARMV7_IMM16(x) (extract32((x), 0, 12) | \
+ extract32((x), 12, 4) << 16)
+
+/* Write immediate val to address r0 + addr. r0 should contain base offset
+ * of the SLCR block. Clobbers r1.
+ */
+
+#define SLCR_WRITE(addr, val) \
+ 0xe3001000 + ARMV7_IMM16(extract32((val), 0, 16)), /* movw r1 ... */ \
+ 0xe3401000 + ARMV7_IMM16(extract32((val), 16, 16)), /* movt r1 ... */ \
+ 0xe5801000 + (addr)
+
+static void zynq_write_board_setup(ARMCPU *cpu,
+ const struct arm_boot_info *info)
+{
+ int n;
+ uint32_t board_setup_blob[] = {
+ 0xe3a004f8, /* mov r0, #0xf8000000 */
+ SLCR_WRITE(SLCR_UNLOCK_OFFSET, SLCR_XILINX_UNLOCK_KEY),
+ SLCR_WRITE(SLCR_ARM_PLL_OFFSET, 0x00014008),
+ SLCR_WRITE(SLCR_LOCK_OFFSET, SLCR_XILINX_LOCK_KEY),
+ 0xe12fff1e, /* bx lr */
+ };
+ for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
+ board_setup_blob[n] = tswap32(board_setup_blob[n]);
+ }
+ rom_add_blob_fixed("board-setup", board_setup_blob,
+ sizeof(board_setup_blob), BOARD_SETUP_ADDR);
+}
+
static struct arm_boot_info zynq_binfo = {};
static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
@@ -113,10 +158,11 @@ static void zynq_init(MachineState *machine)
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
- DeviceState *dev;
+ DeviceState *dev, *carddev;
SysBusDevice *busdev;
+ DriveInfo *di;
+ BlockBackend *blk;
qemu_irq pic[64];
- Error *err = NULL;
int n;
if (!cpu_model) {
@@ -131,29 +177,14 @@ static void zynq_init(MachineState *machine)
* realization.
*/
if (object_property_find(OBJECT(cpu), "has_el3", NULL)) {
- object_property_set_bool(OBJECT(cpu), false, "has_el3", &err);
- if (err) {
- error_report_err(err);
- exit(1);
- }
- }
-
- object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr", &err);
- if (err) {
- error_report_err(err);
- exit(1);
+ object_property_set_bool(OBJECT(cpu), false, "has_el3", &error_fatal);
}
- object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar", &err);
- if (err) {
- error_report_err(err);
- exit(1);
- }
- object_property_set_bool(OBJECT(cpu), true, "realized", &err);
- if (err) {
- error_report_err(err);
- exit(1);
- }
+ object_property_set_int(OBJECT(cpu), ZYNQ_BOARD_MIDR, "midr",
+ &error_fatal);
+ object_property_set_int(OBJECT(cpu), MPCORE_PERIPHBASE, "reset-cbar",
+ &error_fatal);
+ object_property_set_bool(OBJECT(cpu), true, "realized", &error_fatal);
/* max 2GB ram */
if (ram_size > 0x80000000) {
@@ -167,7 +198,7 @@ static void zynq_init(MachineState *machine)
/* 256K of on-chip memory */
memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 << 10,
- &error_abort);
+ &error_fatal);
vmstate_register_ram_global(ocm_ram);
memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
@@ -220,11 +251,28 @@ static void zynq_init(MachineState *machine)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]);
+ di = drive_get_next(IF_SD);
+ blk = di ? blk_by_legacy_dinfo(di) : NULL;
+ carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
+ qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
+ object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
+
dev = qdev_create(NULL, "generic-sdhci");
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]);
+ di = drive_get_next(IF_SD);
+ blk = di ? blk_by_legacy_dinfo(di) : NULL;
+ carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
+ qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
+ object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
+
+ dev = qdev_create(NULL, TYPE_ZYNQ_XADC);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-IRQ_OFFSET]);
+
dev = qdev_create(NULL, "pl330");
qdev_prop_set_uint8(dev, "num_chnls", 8);
qdev_prop_set_uint8(dev, "num_periph_req", 4);
@@ -252,21 +300,19 @@ static void zynq_init(MachineState *machine)
zynq_binfo.nb_cpus = 1;
zynq_binfo.board_id = 0xd32;
zynq_binfo.loader_start = 0;
+ zynq_binfo.board_setup_addr = BOARD_SETUP_ADDR;
+ zynq_binfo.write_board_setup = zynq_write_board_setup;
+
arm_load_kernel(ARM_CPU(first_cpu), &zynq_binfo);
}
-static QEMUMachine zynq_machine = {
- .name = "xilinx-zynq-a9",
- .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9",
- .init = zynq_init,
- .block_default_type = IF_SCSI,
- .max_cpus = 1,
- .no_sdcard = 1,
-};
-
-static void zynq_machine_init(void)
+static void zynq_machine_init(MachineClass *mc)
{
- qemu_register_machine(&zynq_machine);
+ mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9";
+ mc->init = zynq_init;
+ mc->block_default_type = IF_SCSI;
+ mc->max_cpus = 1;
+ mc->no_sdcard = 1;
}
-machine_init(zynq_machine_init);
+DEFINE_MACHINE("xilinx-zynq-a9", zynq_machine_init)