xref: /openbmc/qemu/hw/arm/highbank.c (revision effd60c8)
1 /*
2  * Calxeda Highbank SoC emulation
3  *
4  * Copyright (c) 2010-2012 Calxeda
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2 or later, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "qemu/osdep.h"
21 #include "qemu/datadir.h"
22 #include "qapi/error.h"
23 #include "hw/sysbus.h"
24 #include "migration/vmstate.h"
25 #include "hw/arm/boot.h"
26 #include "hw/loader.h"
27 #include "net/net.h"
28 #include "sysemu/runstate.h"
29 #include "sysemu/sysemu.h"
30 #include "hw/boards.h"
31 #include "qemu/error-report.h"
32 #include "hw/char/pl011.h"
33 #include "hw/ide/ahci.h"
34 #include "hw/cpu/a9mpcore.h"
35 #include "hw/cpu/a15mpcore.h"
36 #include "qemu/log.h"
37 #include "qom/object.h"
38 #include "cpu.h"
39 
40 #define SMP_BOOT_ADDR           0x100
41 #define SMP_BOOT_REG            0x40
42 #define MPCORE_PERIPHBASE       0xfff10000
43 
44 #define MVBAR_ADDR              0x200
45 #define BOARD_SETUP_ADDR        (MVBAR_ADDR + 8 * sizeof(uint32_t))
46 
47 #define NIRQ_GIC                160
48 
49 /* Board init.  */
50 
51 #define NUM_REGS      0x200
52 static void hb_regs_write(void *opaque, hwaddr offset,
53                           uint64_t value, unsigned size)
54 {
55     uint32_t *regs = opaque;
56 
57     if (offset == 0xf00) {
58         if (value == 1 || value == 2) {
59             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
60         } else if (value == 3) {
61             qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
62         }
63     }
64 
65     if (offset / 4 >= NUM_REGS) {
66         qemu_log_mask(LOG_GUEST_ERROR,
67                   "highbank: bad write offset 0x%" HWADDR_PRIx "\n", offset);
68         return;
69     }
70     regs[offset / 4] = value;
71 }
72 
73 static uint64_t hb_regs_read(void *opaque, hwaddr offset,
74                              unsigned size)
75 {
76     uint32_t value;
77     uint32_t *regs = opaque;
78 
79     if (offset / 4 >= NUM_REGS) {
80         qemu_log_mask(LOG_GUEST_ERROR,
81                   "highbank: bad read offset 0x%" HWADDR_PRIx "\n", offset);
82         return 0;
83     }
84     value = regs[offset / 4];
85 
86     if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) {
87         value |= 0x30000000;
88     }
89 
90     return value;
91 }
92 
93 static const MemoryRegionOps hb_mem_ops = {
94     .read = hb_regs_read,
95     .write = hb_regs_write,
96     .endianness = DEVICE_NATIVE_ENDIAN,
97 };
98 
99 #define TYPE_HIGHBANK_REGISTERS "highbank-regs"
100 OBJECT_DECLARE_SIMPLE_TYPE(HighbankRegsState, HIGHBANK_REGISTERS)
101 
102 struct HighbankRegsState {
103     /*< private >*/
104     SysBusDevice parent_obj;
105     /*< public >*/
106 
107     MemoryRegion iomem;
108     uint32_t regs[NUM_REGS];
109 };
110 
111 static const VMStateDescription vmstate_highbank_regs = {
112     .name = "highbank-regs",
113     .version_id = 0,
114     .minimum_version_id = 0,
115     .fields = (const VMStateField[]) {
116         VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
117         VMSTATE_END_OF_LIST(),
118     },
119 };
120 
121 static void highbank_regs_reset(DeviceState *dev)
122 {
123     HighbankRegsState *s = HIGHBANK_REGISTERS(dev);
124 
125     s->regs[0x40] = 0x05F20121;
126     s->regs[0x41] = 0x2;
127     s->regs[0x42] = 0x05F30121;
128     s->regs[0x43] = 0x05F40121;
129 }
130 
131 static void highbank_regs_init(Object *obj)
132 {
133     HighbankRegsState *s = HIGHBANK_REGISTERS(obj);
134     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
135 
136     memory_region_init_io(&s->iomem, obj, &hb_mem_ops, s->regs,
137                           "highbank_regs", 0x1000);
138     sysbus_init_mmio(dev, &s->iomem);
139 }
140 
141 static void highbank_regs_class_init(ObjectClass *klass, void *data)
142 {
143     DeviceClass *dc = DEVICE_CLASS(klass);
144 
145     dc->desc = "Calxeda Highbank registers";
146     dc->vmsd = &vmstate_highbank_regs;
147     dc->reset = highbank_regs_reset;
148 }
149 
150 static const TypeInfo highbank_regs_info = {
151     .name          = TYPE_HIGHBANK_REGISTERS,
152     .parent        = TYPE_SYS_BUS_DEVICE,
153     .instance_size = sizeof(HighbankRegsState),
154     .instance_init = highbank_regs_init,
155     .class_init    = highbank_regs_class_init,
156 };
157 
158 static void highbank_regs_register_types(void)
159 {
160     type_register_static(&highbank_regs_info);
161 }
162 
163 type_init(highbank_regs_register_types)
164 
165 static struct arm_boot_info highbank_binfo;
166 
167 enum cxmachines {
168     CALXEDA_HIGHBANK,
169     CALXEDA_MIDWAY,
170 };
171 
172 /* ram_size must be set to match the upper bound of memory in the
173  * device tree (linux/arch/arm/boot/dts/highbank.dts), which is
174  * normally 0xff900000 or -m 4089. When running this board on a
175  * 32-bit host, set the reg value of memory to 0xf7ff00000 in the
176  * device tree and pass -m 2047 to QEMU.
177  */
178 static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
179 {
180     DeviceState *dev = NULL;
181     SysBusDevice *busdev;
182     qemu_irq pic[128];
183     int n;
184     unsigned int smp_cpus = machine->smp.cpus;
185     qemu_irq cpu_irq[4];
186     qemu_irq cpu_fiq[4];
187     qemu_irq cpu_virq[4];
188     qemu_irq cpu_vfiq[4];
189     MemoryRegion *sysram;
190     MemoryRegion *sysmem;
191     char *sysboot_filename;
192 
193     switch (machine_id) {
194     case CALXEDA_HIGHBANK:
195         machine->cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
196         break;
197     case CALXEDA_MIDWAY:
198         machine->cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
199         break;
200     default:
201         assert(0);
202     }
203 
204     for (n = 0; n < smp_cpus; n++) {
205         Object *cpuobj;
206         ARMCPU *cpu;
207 
208         cpuobj = object_new(machine->cpu_type);
209         cpu = ARM_CPU(cpuobj);
210 
211         object_property_set_int(cpuobj, "psci-conduit", QEMU_PSCI_CONDUIT_SMC,
212                                 &error_abort);
213 
214         if (object_property_find(cpuobj, "reset-cbar")) {
215             object_property_set_int(cpuobj, "reset-cbar", MPCORE_PERIPHBASE,
216                                     &error_abort);
217         }
218         qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
219         cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
220         cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ);
221         cpu_virq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_VIRQ);
222         cpu_vfiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_VFIQ);
223     }
224 
225     sysmem = get_system_memory();
226     /* SDRAM at address zero.  */
227     memory_region_add_subregion(sysmem, 0, machine->ram);
228 
229     sysram = g_new(MemoryRegion, 1);
230     memory_region_init_ram(sysram, NULL, "highbank.sysram", 0x8000,
231                            &error_fatal);
232     memory_region_add_subregion(sysmem, 0xfff88000, sysram);
233     if (machine->firmware != NULL) {
234         sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, machine->firmware);
235         if (sysboot_filename != NULL) {
236             if (load_image_targphys(sysboot_filename, 0xfff88000, 0x8000) < 0) {
237                 error_report("Unable to load %s", machine->firmware);
238                 exit(1);
239             }
240             g_free(sysboot_filename);
241         } else {
242             error_report("Unable to find %s", machine->firmware);
243             exit(1);
244         }
245     }
246 
247     switch (machine_id) {
248     case CALXEDA_HIGHBANK:
249         dev = qdev_new("l2x0");
250         busdev = SYS_BUS_DEVICE(dev);
251         sysbus_realize_and_unref(busdev, &error_fatal);
252         sysbus_mmio_map(busdev, 0, 0xfff12000);
253 
254         dev = qdev_new(TYPE_A9MPCORE_PRIV);
255         break;
256     case CALXEDA_MIDWAY:
257         dev = qdev_new(TYPE_A15MPCORE_PRIV);
258         break;
259     }
260     qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
261     qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
262     busdev = SYS_BUS_DEVICE(dev);
263     sysbus_realize_and_unref(busdev, &error_fatal);
264     sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
265     for (n = 0; n < smp_cpus; n++) {
266         sysbus_connect_irq(busdev, n, cpu_irq[n]);
267         sysbus_connect_irq(busdev, n + smp_cpus, cpu_fiq[n]);
268         sysbus_connect_irq(busdev, n + 2 * smp_cpus, cpu_virq[n]);
269         sysbus_connect_irq(busdev, n + 3 * smp_cpus, cpu_vfiq[n]);
270     }
271 
272     for (n = 0; n < 128; n++) {
273         pic[n] = qdev_get_gpio_in(dev, n);
274     }
275 
276     dev = qdev_new("sp804");
277     qdev_prop_set_uint32(dev, "freq0", 150000000);
278     qdev_prop_set_uint32(dev, "freq1", 150000000);
279     busdev = SYS_BUS_DEVICE(dev);
280     sysbus_realize_and_unref(busdev, &error_fatal);
281     sysbus_mmio_map(busdev, 0, 0xfff34000);
282     sysbus_connect_irq(busdev, 0, pic[18]);
283     pl011_create(0xfff36000, pic[20], serial_hd(0));
284 
285     dev = qdev_new(TYPE_HIGHBANK_REGISTERS);
286     busdev = SYS_BUS_DEVICE(dev);
287     sysbus_realize_and_unref(busdev, &error_fatal);
288     sysbus_mmio_map(busdev, 0, 0xfff3c000);
289 
290     sysbus_create_simple("pl061", 0xfff30000, pic[14]);
291     sysbus_create_simple("pl061", 0xfff31000, pic[15]);
292     sysbus_create_simple("pl061", 0xfff32000, pic[16]);
293     sysbus_create_simple("pl061", 0xfff33000, pic[17]);
294     sysbus_create_simple("pl031", 0xfff35000, pic[19]);
295     sysbus_create_simple("pl022", 0xfff39000, pic[23]);
296 
297     sysbus_create_simple(TYPE_SYSBUS_AHCI, 0xffe08000, pic[83]);
298 
299     if (nd_table[0].used) {
300         qemu_check_nic_model(&nd_table[0], "xgmac");
301         dev = qdev_new("xgmac");
302         qdev_set_nic_properties(dev, &nd_table[0]);
303         sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
304         sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000);
305         sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]);
306         sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]);
307         sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[79]);
308 
309         qemu_check_nic_model(&nd_table[1], "xgmac");
310         dev = qdev_new("xgmac");
311         qdev_set_nic_properties(dev, &nd_table[1]);
312         sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
313         sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000);
314         sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]);
315         sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]);
316         sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[82]);
317     }
318 
319     /* TODO create and connect IDE devices for ide_drive_get() */
320 
321     highbank_binfo.ram_size = machine->ram_size;
322     /* highbank requires a dtb in order to boot, and the dtb will override
323      * the board ID. The following value is ignored, so set it to -1 to be
324      * clear that the value is meaningless.
325      */
326     highbank_binfo.board_id = -1;
327     highbank_binfo.loader_start = 0;
328     highbank_binfo.board_setup_addr = BOARD_SETUP_ADDR;
329     highbank_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
330 
331     arm_load_kernel(ARM_CPU(first_cpu), machine, &highbank_binfo);
332 }
333 
334 static void highbank_init(MachineState *machine)
335 {
336     calxeda_init(machine, CALXEDA_HIGHBANK);
337 }
338 
339 static void midway_init(MachineState *machine)
340 {
341     calxeda_init(machine, CALXEDA_MIDWAY);
342 }
343 
344 static void highbank_class_init(ObjectClass *oc, void *data)
345 {
346     MachineClass *mc = MACHINE_CLASS(oc);
347 
348     mc->desc = "Calxeda Highbank (ECX-1000)";
349     mc->init = highbank_init;
350     mc->block_default_type = IF_IDE;
351     mc->units_per_default_bus = 1;
352     mc->max_cpus = 4;
353     mc->ignore_memory_transaction_failures = true;
354     mc->default_ram_id = "highbank.dram";
355 }
356 
357 static const TypeInfo highbank_type = {
358     .name = MACHINE_TYPE_NAME("highbank"),
359     .parent = TYPE_MACHINE,
360     .class_init = highbank_class_init,
361 };
362 
363 static void midway_class_init(ObjectClass *oc, void *data)
364 {
365     MachineClass *mc = MACHINE_CLASS(oc);
366 
367     mc->desc = "Calxeda Midway (ECX-2000)";
368     mc->init = midway_init;
369     mc->block_default_type = IF_IDE;
370     mc->units_per_default_bus = 1;
371     mc->max_cpus = 4;
372     mc->ignore_memory_transaction_failures = true;
373     mc->default_ram_id = "highbank.dram";
374 }
375 
376 static const TypeInfo midway_type = {
377     .name = MACHINE_TYPE_NAME("midway"),
378     .parent = TYPE_MACHINE,
379     .class_init = midway_class_init,
380 };
381 
382 static void calxeda_machines_init(void)
383 {
384     type_register_static(&highbank_type);
385     type_register_static(&midway_type);
386 }
387 
388 type_init(calxeda_machines_init)
389