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