qemu/hw/arm/digic.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the Canon DIGIC SoC.
   3 *
   4 * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
   5 *
   6 * This model is based on reverse engineering efforts
   7 * made by CHDK (http://chdk.wikia.com) and
   8 * Magic Lantern (http://www.magiclantern.fm) projects
   9 * contributors.
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19 * GNU General Public License for more details.
  20 *
  21 */
  22
  23#include "qemu/osdep.h"
  24#include "qapi/error.h"
  25#include "hw/arm/digic.h"
  26
  27#define DIGIC4_TIMER_BASE(n)    (0xc0210000 + (n) * 0x100)
  28
  29#define DIGIC_UART_BASE          0xc0800000
  30
  31static void digic_init(Object *obj)
  32{
  33    DigicState *s = DIGIC(obj);
  34    DeviceState *dev;
  35    int i;
  36
  37    object_initialize(&s->cpu, sizeof(s->cpu), "arm946-" TYPE_ARM_CPU);
  38    object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
  39
  40    for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
  41#define DIGIC_TIMER_NAME_MLEN    11
  42        char name[DIGIC_TIMER_NAME_MLEN];
  43
  44        object_initialize(&s->timer[i], sizeof(s->timer[i]), TYPE_DIGIC_TIMER);
  45        dev = DEVICE(&s->timer[i]);
  46        qdev_set_parent_bus(dev, sysbus_get_default());
  47        snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]", i);
  48        object_property_add_child(obj, name, OBJECT(&s->timer[i]), NULL);
  49    }
  50
  51    object_initialize(&s->uart, sizeof(s->uart), TYPE_DIGIC_UART);
  52    dev = DEVICE(&s->uart);
  53    qdev_set_parent_bus(dev, sysbus_get_default());
  54    object_property_add_child(obj, "uart", OBJECT(&s->uart), NULL);
  55}
  56
  57static void digic_realize(DeviceState *dev, Error **errp)
  58{
  59    DigicState *s = DIGIC(dev);
  60    Error *err = NULL;
  61    SysBusDevice *sbd;
  62    int i;
  63
  64    object_property_set_bool(OBJECT(&s->cpu), true, "reset-hivecs", &err);
  65    if (err != NULL) {
  66        error_propagate(errp, err);
  67        return;
  68    }
  69
  70    object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
  71    if (err != NULL) {
  72        error_propagate(errp, err);
  73        return;
  74    }
  75
  76    for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
  77        object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
  78        if (err != NULL) {
  79            error_propagate(errp, err);
  80            return;
  81        }
  82
  83        sbd = SYS_BUS_DEVICE(&s->timer[i]);
  84        sysbus_mmio_map(sbd, 0, DIGIC4_TIMER_BASE(i));
  85    }
  86
  87    object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
  88    if (err != NULL) {
  89        error_propagate(errp, err);
  90        return;
  91    }
  92
  93    sbd = SYS_BUS_DEVICE(&s->uart);
  94    sysbus_mmio_map(sbd, 0, DIGIC_UART_BASE);
  95}
  96
  97static void digic_class_init(ObjectClass *oc, void *data)
  98{
  99    DeviceClass *dc = DEVICE_CLASS(oc);
 100
 101    dc->realize = digic_realize;
 102
 103    /*
 104     * Reason: creates an ARM CPU, thus use after free(), see
 105     * arm_cpu_class_init()
 106     */
 107    dc->cannot_destroy_with_object_finalize_yet = true;
 108}
 109
 110static const TypeInfo digic_type_info = {
 111    .name = TYPE_DIGIC,
 112    .parent = TYPE_DEVICE,
 113    .instance_size = sizeof(DigicState),
 114    .instance_init = digic_init,
 115    .class_init = digic_class_init,
 116};
 117
 118static void digic_register_types(void)
 119{
 120    type_register_static(&digic_type_info);
 121}
 122
 123type_init(digic_register_types)
 124