1 | /* |
2 | * Allwinner A10 SoC emulation |
3 | * |
4 | * Copyright (C) 2013 Li Guang |
5 | * Written by Li Guang <lig.fnst@cn.fujitsu.com> |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify it |
8 | * under the terms of the GNU General Public License as published by the |
9 | * Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. |
11 | * |
12 | * This program is distributed in the hope that it will be useful, but WITHOUT |
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | * for more details. |
16 | */ |
17 | |
18 | #include "qemu/osdep.h" |
19 | #include "exec/address-spaces.h" |
20 | #include "qapi/error.h" |
21 | #include "qemu/module.h" |
22 | #include "cpu.h" |
23 | #include "hw/sysbus.h" |
24 | #include "hw/arm/allwinner-a10.h" |
25 | #include "hw/misc/unimp.h" |
26 | #include "sysemu/sysemu.h" |
27 | |
28 | static void aw_a10_init(Object *obj) |
29 | { |
30 | AwA10State *s = AW_A10(obj); |
31 | |
32 | object_initialize_child(obj, "cpu" , &s->cpu, sizeof(s->cpu), |
33 | ARM_CPU_TYPE_NAME("cortex-a8" ), |
34 | &error_abort, NULL); |
35 | |
36 | sysbus_init_child_obj(obj, "intc" , &s->intc, sizeof(s->intc), |
37 | TYPE_AW_A10_PIC); |
38 | |
39 | sysbus_init_child_obj(obj, "timer" , &s->timer, sizeof(s->timer), |
40 | TYPE_AW_A10_PIT); |
41 | |
42 | sysbus_init_child_obj(obj, "emac" , &s->emac, sizeof(s->emac), TYPE_AW_EMAC); |
43 | |
44 | sysbus_init_child_obj(obj, "sata" , &s->sata, sizeof(s->sata), |
45 | TYPE_ALLWINNER_AHCI); |
46 | } |
47 | |
48 | static void aw_a10_realize(DeviceState *dev, Error **errp) |
49 | { |
50 | AwA10State *s = AW_A10(dev); |
51 | SysBusDevice *sysbusdev; |
52 | uint8_t i; |
53 | qemu_irq fiq, irq; |
54 | Error *err = NULL; |
55 | |
56 | object_property_set_bool(OBJECT(&s->cpu), true, "realized" , &err); |
57 | if (err != NULL) { |
58 | error_propagate(errp, err); |
59 | return; |
60 | } |
61 | irq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ); |
62 | fiq = qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ); |
63 | |
64 | object_property_set_bool(OBJECT(&s->intc), true, "realized" , &err); |
65 | if (err != NULL) { |
66 | error_propagate(errp, err); |
67 | return; |
68 | } |
69 | sysbusdev = SYS_BUS_DEVICE(&s->intc); |
70 | sysbus_mmio_map(sysbusdev, 0, AW_A10_PIC_REG_BASE); |
71 | sysbus_connect_irq(sysbusdev, 0, irq); |
72 | sysbus_connect_irq(sysbusdev, 1, fiq); |
73 | for (i = 0; i < AW_A10_PIC_INT_NR; i++) { |
74 | s->irq[i] = qdev_get_gpio_in(DEVICE(&s->intc), i); |
75 | } |
76 | |
77 | object_property_set_bool(OBJECT(&s->timer), true, "realized" , &err); |
78 | if (err != NULL) { |
79 | error_propagate(errp, err); |
80 | return; |
81 | } |
82 | sysbusdev = SYS_BUS_DEVICE(&s->timer); |
83 | sysbus_mmio_map(sysbusdev, 0, AW_A10_PIT_REG_BASE); |
84 | sysbus_connect_irq(sysbusdev, 0, s->irq[22]); |
85 | sysbus_connect_irq(sysbusdev, 1, s->irq[23]); |
86 | sysbus_connect_irq(sysbusdev, 2, s->irq[24]); |
87 | sysbus_connect_irq(sysbusdev, 3, s->irq[25]); |
88 | sysbus_connect_irq(sysbusdev, 4, s->irq[67]); |
89 | sysbus_connect_irq(sysbusdev, 5, s->irq[68]); |
90 | |
91 | memory_region_init_ram(&s->sram_a, OBJECT(dev), "sram A" , 48 * KiB, |
92 | &error_fatal); |
93 | memory_region_add_subregion(get_system_memory(), 0x00000000, &s->sram_a); |
94 | create_unimplemented_device("a10-sram-ctrl" , 0x01c00000, 4 * KiB); |
95 | |
96 | /* FIXME use qdev NIC properties instead of nd_table[] */ |
97 | if (nd_table[0].used) { |
98 | qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC); |
99 | qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); |
100 | } |
101 | object_property_set_bool(OBJECT(&s->emac), true, "realized" , &err); |
102 | if (err != NULL) { |
103 | error_propagate(errp, err); |
104 | return; |
105 | } |
106 | sysbusdev = SYS_BUS_DEVICE(&s->emac); |
107 | sysbus_mmio_map(sysbusdev, 0, AW_A10_EMAC_BASE); |
108 | sysbus_connect_irq(sysbusdev, 0, s->irq[55]); |
109 | |
110 | object_property_set_bool(OBJECT(&s->sata), true, "realized" , &err); |
111 | if (err) { |
112 | error_propagate(errp, err); |
113 | return; |
114 | } |
115 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, AW_A10_SATA_BASE); |
116 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, s->irq[56]); |
117 | |
118 | /* FIXME use a qdev chardev prop instead of serial_hd() */ |
119 | serial_mm_init(get_system_memory(), AW_A10_UART0_REG_BASE, 2, s->irq[1], |
120 | 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN); |
121 | } |
122 | |
123 | static void aw_a10_class_init(ObjectClass *oc, void *data) |
124 | { |
125 | DeviceClass *dc = DEVICE_CLASS(oc); |
126 | |
127 | dc->realize = aw_a10_realize; |
128 | /* Reason: Uses serial_hds and nd_table in realize function */ |
129 | dc->user_creatable = false; |
130 | } |
131 | |
132 | static const TypeInfo aw_a10_type_info = { |
133 | .name = TYPE_AW_A10, |
134 | .parent = TYPE_DEVICE, |
135 | .instance_size = sizeof(AwA10State), |
136 | .instance_init = aw_a10_init, |
137 | .class_init = aw_a10_class_init, |
138 | }; |
139 | |
140 | static void aw_a10_register_types(void) |
141 | { |
142 | type_register_static(&aw_a10_type_info); |
143 | } |
144 | |
145 | type_init(aw_a10_register_types) |
146 | |