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#include "sysemu/sysemu.h"
  27
  28#define DIGIC4_TIMER_BASE(n)    (0xc0210000 + (n) * 0x100)
  29
  30#define DIGIC_UART_BASE          0xc0800000
  31
  32static void digic_init(Object *obj)
  33{
  34    DigicState *s = DIGIC(obj);
  35    DeviceState *dev;
  36    int i;
  37
  38    object_initialize(&s->cpu, sizeof(s->cpu), "arm946-" TYPE_ARM_CPU);
  39    object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
  40
  41    for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
  42#define DIGIC_TIMER_NAME_MLEN    11
  43        char name[DIGIC_TIMER_NAME_MLEN];
  44
  45        object_initialize(&s->timer[i], sizeof(s->timer[i]), TYPE_DIGIC_TIMER);
  46        dev = DEVICE(&s->timer[i]);
  47        qdev_set_parent_bus(dev, sysbus_get_default());
  48        snprintf(name, DIGIC_TIMER_NAME_MLEN, "timer[%d]", i);
  49        object_property_add_child(obj, name, OBJECT(&s->timer[i]), NULL);
  50    }
  51
  52    object_initialize(&s->uart, sizeof(s->uart), TYPE_DIGIC_UART);
  53    dev = DEVICE(&s->uart);
  54    qdev_set_parent_bus(dev, sysbus_get_default());
  55    object_property_add_child(obj, "uart", OBJECT(&s->uart), NULL);
  56}
  57
  58static void digic_realize(DeviceState *dev, Error **errp)
  59{
  60    DigicState *s = DIGIC(dev);
  61    Error *err = NULL;
  62    SysBusDevice *sbd;
  63    int i;
  64
  65    object_property_set_bool(OBJECT(&s->cpu), true, "reset-hivecs", &err);
  66    if (err != NULL) {
  67        error_propagate(errp, err);
  68        return;
  69    }
  70
  71    object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
  72    if (err != NULL) {
  73        error_propagate(errp, err);
  74        return;
  75    }
  76
  77    for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
  78        object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
  79        if (err != NULL) {
  80            error_propagate(errp, err);
  81            return;
  82        }
  83
  84        sbd = SYS_BUS_DEVICE(&s->timer[i]);
  85        sysbus_mmio_map(sbd, 0, DIGIC4_TIMER_BASE(i));
  86    }
  87
  88    qdev_prop_set_chr(DEVICE(&s->uart), "chardev", serial_hd(0));
  89    object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
  90    if (err != NULL) {
  91        error_propagate(errp, err);
  92        return;
  93    }
  94
  95    sbd = SYS_BUS_DEVICE(&s->uart);
  96    sysbus_mmio_map(sbd, 0, DIGIC_UART_BASE);
  97}
  98
  99static void digic_class_init(ObjectClass *oc, void *data)
 100{
 101    DeviceClass *dc = DEVICE_CLASS(oc);
 102
 103    dc->realize = digic_realize;
 104    /* Reason: Uses serial_hds in the realize function --> not usable twice */
 105    dc->user_creatable = false;
 106}
 107
 108static const TypeInfo digic_type_info = {
 109    .name = TYPE_DIGIC,
 110    .parent = TYPE_DEVICE,
 111    .instance_size = sizeof(DigicState),
 112    .instance_init = digic_init,
 113    .class_init = digic_class_init,
 114};
 115
 116static void digic_register_types(void)
 117{
 118    type_register_static(&digic_type_info);
 119}
 120
 121type_init(digic_register_types)
 122