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