xlnx-zynqmp.c 14.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Xilinx Zynq MPSoC emulation
 *
 * Copyright (C) 2015 Xilinx Inc
 * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
 *
 * 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.
 */

P
Peter Maydell 已提交
18
#include "qemu/osdep.h"
19
#include "qapi/error.h"
20 21
#include "qemu-common.h"
#include "cpu.h"
22
#include "hw/arm/xlnx-zynqmp.h"
23
#include "hw/intc/arm_gic_common.h"
P
Peter Crosthwaite 已提交
24
#include "exec/address-spaces.h"
25 26
#include "sysemu/kvm.h"
#include "kvm_arm.h"
P
Peter Crosthwaite 已提交
27 28 29

#define GIC_NUM_SPI_INTR 160

30 31 32
#define ARM_PHYS_TIMER_PPI  30
#define ARM_VIRT_TIMER_PPI  27

P
Peter Crosthwaite 已提交
33 34 35 36
#define GIC_BASE_ADDR       0xf9000000
#define GIC_DIST_ADDR       0xf9010000
#define GIC_CPU_ADDR        0xf9020000

37 38 39 40
#define SATA_INTR           133
#define SATA_ADDR           0xFD0C0000
#define SATA_NUM_PORTS      2

41 42 43 44 45 46 47 48
static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
    0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000,
};

static const int gem_intr[XLNX_ZYNQMP_NUM_GEMS] = {
    57, 59, 61, 63,
};

49 50 51 52 53 54 55 56
static const uint64_t uart_addr[XLNX_ZYNQMP_NUM_UARTS] = {
    0xFF000000, 0xFF010000,
};

static const int uart_intr[XLNX_ZYNQMP_NUM_UARTS] = {
    21, 22,
};

57 58 59 60 61 62 63 64
static const uint64_t sdhci_addr[XLNX_ZYNQMP_NUM_SDHCI] = {
    0xFF160000, 0xFF170000,
};

static const int sdhci_intr[XLNX_ZYNQMP_NUM_SDHCI] = {
    48, 49,
};

65 66 67 68 69 70 71 72
static const uint64_t spi_addr[XLNX_ZYNQMP_NUM_SPIS] = {
    0xFF040000, 0xFF050000,
};

static const int spi_intr[XLNX_ZYNQMP_NUM_SPIS] = {
    19, 20,
};

P
Peter Crosthwaite 已提交
73 74 75 76 77 78 79 80 81
typedef struct XlnxZynqMPGICRegion {
    int region_index;
    uint32_t address;
} XlnxZynqMPGICRegion;

static const XlnxZynqMPGICRegion xlnx_zynqmp_gic_regions[] = {
    { .region_index = 0, .address = GIC_DIST_ADDR, },
    { .region_index = 1, .address = GIC_CPU_ADDR,  },
};
82

83 84 85 86 87
static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index)
{
    return GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index;
}

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
static void xlnx_zynqmp_create_rpu(XlnxZynqMPState *s, const char *boot_cpu,
                                   Error **errp)
{
    Error *err = NULL;
    int i;

    for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) {
        char *name;

        object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]),
                          "cortex-r5-" TYPE_ARM_CPU);
        object_property_add_child(OBJECT(s), "rpu-cpu[*]",
                                  OBJECT(&s->rpu_cpu[i]), &error_abort);

        name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
        if (strcmp(name, boot_cpu)) {
            /* Secondary CPUs start in PSCI powered-down state */
            object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true,
                                     "start-powered-off", &error_abort);
        } else {
            s->boot_cpu_ptr = &s->rpu_cpu[i];
        }
        g_free(name);

        object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs",
                                 &error_abort);
        object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized",
                                 &err);
        if (err) {
            error_propagate(errp, err);
            return;
        }
    }
}

123 124 125 126 127
static void xlnx_zynqmp_init(Object *obj)
{
    XlnxZynqMPState *s = XLNX_ZYNQMP(obj);
    int i;

128 129
    for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) {
        object_initialize(&s->apu_cpu[i], sizeof(s->apu_cpu[i]),
130
                          "cortex-a53-" TYPE_ARM_CPU);
131
        object_property_add_child(obj, "apu-cpu[*]", OBJECT(&s->apu_cpu[i]),
132 133
                                  &error_abort);
    }
P
Peter Crosthwaite 已提交
134

135 136 137 138 139
    object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION,
                             (Object **)&s->ddr_ram,
                             qdev_prop_allow_set_link_before_realize,
                             OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);

140
    object_initialize(&s->gic, sizeof(s->gic), gic_class_name());
P
Peter Crosthwaite 已提交
141
    qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
142 143 144 145 146

    for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
        object_initialize(&s->gem[i], sizeof(s->gem[i]), TYPE_CADENCE_GEM);
        qdev_set_parent_bus(DEVICE(&s->gem[i]), sysbus_get_default());
    }
147 148 149 150 151

    for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
        object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_CADENCE_UART);
        qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
    }
152 153 154

    object_initialize(&s->sata, sizeof(s->sata), TYPE_SYSBUS_AHCI);
    qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default());
155 156 157 158 159 160 161

    for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
        object_initialize(&s->sdhci[i], sizeof(s->sdhci[i]),
                          TYPE_SYSBUS_SDHCI);
        qdev_set_parent_bus(DEVICE(&s->sdhci[i]),
                            sysbus_get_default());
    }
162 163 164 165 166 167

    for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
        object_initialize(&s->spi[i], sizeof(s->spi[i]),
                          TYPE_XILINX_SPIPS);
        qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
    }
168 169 170 171 172
}

static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
{
    XlnxZynqMPState *s = XLNX_ZYNQMP(dev);
P
Peter Crosthwaite 已提交
173
    MemoryRegion *system_memory = get_system_memory();
174
    uint8_t i;
175
    uint64_t ram_size;
176
    const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]";
177
    ram_addr_t ddr_low_size, ddr_high_size;
178
    qemu_irq gic_spi[GIC_NUM_SPI_INTR];
179 180
    Error *err = NULL;

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
    ram_size = memory_region_size(s->ddr_ram);

    /* Create the DDR Memory Regions. User friendly checks should happen at
     * the board level
     */
    if (ram_size > XLNX_ZYNQMP_MAX_LOW_RAM_SIZE) {
        /* The RAM size is above the maximum available for the low DDR.
         * Create the high DDR memory region as well.
         */
        assert(ram_size <= XLNX_ZYNQMP_MAX_RAM_SIZE);
        ddr_low_size = XLNX_ZYNQMP_MAX_LOW_RAM_SIZE;
        ddr_high_size = ram_size - XLNX_ZYNQMP_MAX_LOW_RAM_SIZE;

        memory_region_init_alias(&s->ddr_ram_high, NULL,
                                 "ddr-ram-high", s->ddr_ram,
                                  ddr_low_size, ddr_high_size);
        memory_region_add_subregion(get_system_memory(),
                                    XLNX_ZYNQMP_HIGH_RAM_START,
                                    &s->ddr_ram_high);
    } else {
        /* RAM must be non-zero */
        assert(ram_size);
        ddr_low_size = ram_size;
    }

    memory_region_init_alias(&s->ddr_ram_low, NULL,
                             "ddr-ram-low", s->ddr_ram,
                              0, ddr_low_size);
    memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram_low);

211 212 213 214 215
    /* Create the four OCM banks */
    for (i = 0; i < XLNX_ZYNQMP_NUM_OCM_BANKS; i++) {
        char *ocm_name = g_strdup_printf("zynqmp.ocm_ram_bank_%d", i);

        memory_region_init_ram(&s->ocm_ram[i], NULL, ocm_name,
216
                               XLNX_ZYNQMP_OCM_RAM_SIZE, &error_fatal);
217 218 219 220 221 222 223 224 225
        vmstate_register_ram_global(&s->ocm_ram[i]);
        memory_region_add_subregion(get_system_memory(),
                                    XLNX_ZYNQMP_OCM_RAM_0_ADDRESS +
                                        i * XLNX_ZYNQMP_OCM_RAM_SIZE,
                                    &s->ocm_ram[i]);

        g_free(ocm_name);
    }

P
Peter Crosthwaite 已提交
226 227
    qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32);
    qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2);
228
    qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS);
P
Peter Crosthwaite 已提交
229

230
    /* Realize APUs before realizing the GIC. KVM requires this.  */
231
    for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) {
232
        char *name;
233

234
        object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC,
235
                                "psci-conduit", &error_abort);
236 237 238

        name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i]));
        if (strcmp(name, boot_cpu)) {
239
            /* Secondary CPUs start in PSCI powered-down state */
240
            object_property_set_bool(OBJECT(&s->apu_cpu[i]), true,
241
                                     "start-powered-off", &error_abort);
242 243
        } else {
            s->boot_cpu_ptr = &s->apu_cpu[i];
244
        }
G
Gonglei 已提交
245
        g_free(name);
246

247 248
        object_property_set_bool(OBJECT(&s->apu_cpu[i]),
                                 s->secure, "has_el3", NULL);
249
        object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR,
250
                                "reset-cbar", &error_abort);
251 252
        object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized",
                                 &err);
253
        if (err) {
254
            error_propagate(errp, err);
255 256
            return;
        }
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
    }

    object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
    if (err) {
        error_propagate(errp, err);
        return;
    }

    assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS);
    for (i = 0; i < XLNX_ZYNQMP_GIC_REGIONS; i++) {
        SysBusDevice *gic = SYS_BUS_DEVICE(&s->gic);
        const XlnxZynqMPGICRegion *r = &xlnx_zynqmp_gic_regions[i];
        MemoryRegion *mr = sysbus_mmio_get_region(gic, r->region_index);
        uint32_t addr = r->address;
        int j;

        sysbus_mmio_map(gic, r->region_index, addr);

        for (j = 0; j < XLNX_ZYNQMP_GIC_ALIASES; j++) {
            MemoryRegion *alias = &s->gic_mr[i][j];

            addr += XLNX_ZYNQMP_GIC_REGION_SIZE;
            memory_region_init_alias(alias, OBJECT(s), "zynqmp-gic-alias", mr,
                                     0, XLNX_ZYNQMP_GIC_REGION_SIZE);
            memory_region_add_subregion(system_memory, addr, alias);
        }
    }

    for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) {
        qemu_irq irq;
P
Peter Crosthwaite 已提交
287 288

        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i,
289 290
                           qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]),
                                            ARM_CPU_IRQ));
291 292
        irq = qdev_get_gpio_in(DEVICE(&s->gic),
                               arm_gic_ppi_index(i, ARM_PHYS_TIMER_PPI));
293
        qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 0, irq);
294 295
        irq = qdev_get_gpio_in(DEVICE(&s->gic),
                               arm_gic_ppi_index(i, ARM_VIRT_TIMER_PPI));
296
        qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 1, irq);
297
    }
298

299 300
    if (s->has_rpu) {
        xlnx_zynqmp_create_rpu(s, boot_cpu, &err);
301
        if (err) {
302
            error_propagate(errp, err);
303 304 305 306
            return;
        }
    }

307
    if (!s->boot_cpu_ptr) {
308
        error_setg(errp, "ZynqMP Boot cpu %s not found", boot_cpu);
309 310 311
        return;
    }

312 313 314 315 316 317 318 319 320 321 322 323 324
    for (i = 0; i < GIC_NUM_SPI_INTR; i++) {
        gic_spi[i] = qdev_get_gpio_in(DEVICE(&s->gic), i);
    }

    for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
        NICInfo *nd = &nd_table[i];

        if (nd->used) {
            qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
            qdev_set_nic_properties(DEVICE(&s->gem[i]), nd);
        }
        object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err);
        if (err) {
325
            error_propagate(errp, err);
326 327 328 329 330 331
            return;
        }
        sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]);
        sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0,
                           gic_spi[gem_intr[i]]);
    }
332 333

    for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
334
        qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hds[i]);
335 336
        object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
        if (err) {
337
            error_propagate(errp, err);
338 339 340 341 342 343
            return;
        }
        sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]);
        sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
                           gic_spi[uart_intr[i]]);
    }
344 345 346 347 348 349 350 351 352 353 354

    object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports",
                            &error_abort);
    object_property_set_bool(OBJECT(&s->sata), true, "realized", &err);
    if (err) {
        error_propagate(errp, err);
        return;
    }

    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, SATA_ADDR);
    sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]);
355 356

    for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
357 358
        char *bus_name;

359 360 361 362 363 364 365 366 367 368
        object_property_set_bool(OBJECT(&s->sdhci[i]), true,
                                 "realized", &err);
        if (err) {
            error_propagate(errp, err);
            return;
        }
        sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
                        sdhci_addr[i]);
        sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
                           gic_spi[sdhci_intr[i]]);
369 370 371 372 373 374
        /* Alias controller SD bus to the SoC itself */
        bus_name = g_strdup_printf("sd-bus%d", i);
        object_property_add_alias(OBJECT(s), bus_name,
                                  OBJECT(&s->sdhci[i]), "sd-bus",
                                  &error_abort);
        g_free(bus_name);
375
    }
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

    for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
        gchar *bus_name;

        object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);

        sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]);
        sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
                           gic_spi[spi_intr[i]]);

        /* Alias controller SPI bus to the SoC itself */
        bus_name = g_strdup_printf("spi%d", i);
        object_property_add_alias(OBJECT(s), bus_name,
                                  OBJECT(&s->spi[i]), "spi0",
                                  &error_abort);
	g_free(bus_name);
    }
393 394
}

395 396
static Property xlnx_zynqmp_props[] = {
    DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu),
397
    DEFINE_PROP_BOOL("secure", XlnxZynqMPState, secure, false),
398
    DEFINE_PROP_BOOL("has_rpu", XlnxZynqMPState, has_rpu, false),
399 400 401
    DEFINE_PROP_END_OF_LIST()
};

402 403 404 405
static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(oc);

406
    dc->props = xlnx_zynqmp_props;
407
    dc->realize = xlnx_zynqmp_realize;
408 409 410 411 412 413

    /*
     * Reason: creates an ARM CPU, thus use after free(), see
     * arm_cpu_class_init()
     */
    dc->cannot_destroy_with_object_finalize_yet = true;
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
}

static const TypeInfo xlnx_zynqmp_type_info = {
    .name = TYPE_XLNX_ZYNQMP,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(XlnxZynqMPState),
    .instance_init = xlnx_zynqmp_init,
    .class_init = xlnx_zynqmp_class_init,
};

static void xlnx_zynqmp_register_types(void)
{
    type_register_static(&xlnx_zynqmp_type_info);
}

type_init(xlnx_zynqmp_register_types)