xref: /openbmc/qemu/hw/ppc/virtex_ml507.c (revision 6b829602e2f10f301ff8508f3a6850a0e913142c)
1  /*
2   * Model of Xilinx Virtex5 ML507 PPC-440 refdesign.
3   *
4   * Copyright (c) 2010 Edgar E. Iglesias.
5   *
6   * Permission is hereby granted, free of charge, to any person obtaining a copy
7   * of this software and associated documentation files (the "Software"), to deal
8   * in the Software without restriction, including without limitation the rights
9   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10   * copies of the Software, and to permit persons to whom the Software is
11   * furnished to do so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in
14   * all copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22   * THE SOFTWARE.
23   */
24  
25  #include "qemu/osdep.h"
26  #include "qemu/datadir.h"
27  #include "qemu/units.h"
28  #include "exec/page-protection.h"
29  #include "cpu.h"
30  #include "hw/sysbus.h"
31  #include "hw/char/serial-mm.h"
32  #include "hw/block/flash.h"
33  #include "sysemu/sysemu.h"
34  #include "sysemu/reset.h"
35  #include "hw/boards.h"
36  #include "sysemu/device_tree.h"
37  #include "hw/loader.h"
38  #include "elf.h"
39  #include "qapi/error.h"
40  #include "qemu/error-report.h"
41  #include "qemu/option.h"
42  
43  #include "hw/intc/ppc-uic.h"
44  #include "hw/ppc/ppc.h"
45  #include "hw/ppc/ppc4xx.h"
46  #include "hw/qdev-properties.h"
47  
48  #include <libfdt.h>
49  
50  #define EPAPR_MAGIC    (0x45504150)
51  #define FLASH_SIZE     (16 * MiB)
52  
53  #define INTC_BASEADDR       0x81800000
54  #define UART16550_BASEADDR  0x83e01003
55  #define TIMER_BASEADDR      0x83c00000
56  #define PFLASH_BASEADDR     0xfc000000
57  
58  #define TIMER_IRQ           3
59  #define UART16550_IRQ       9
60  
61  static struct boot_info
62  {
63      uint32_t bootstrap_pc;
64      uint32_t cmdline;
65      uint32_t fdt;
66      uint32_t ima_size;
67      void *vfdt;
68  } boot_info;
69  
ppc440_init_xilinx(const char * cpu_type,uint32_t sysclk)70  static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
71  {
72      PowerPCCPU *cpu;
73      CPUPPCState *env;
74      DeviceState *uicdev;
75      SysBusDevice *uicsbd;
76  
77      cpu = POWERPC_CPU(cpu_create(cpu_type));
78      env = &cpu->env;
79  
80      ppc_booke_timers_init(cpu, sysclk, 0/* no flags */);
81  
82      ppc_dcr_init(env, NULL, NULL);
83  
84      /* interrupt controller */
85      uicdev = qdev_new(TYPE_PPC_UIC);
86      ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uicdev), cpu, &error_fatal);
87      object_unref(OBJECT(uicdev));
88      uicsbd = SYS_BUS_DEVICE(uicdev);
89      sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
90                         qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
91      sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
92                         qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
93  
94      /* This board doesn't wire anything up to the inputs of the UIC. */
95      return cpu;
96  }
97  
main_cpu_reset(void * opaque)98  static void main_cpu_reset(void *opaque)
99  {
100      PowerPCCPU *cpu = opaque;
101      CPUPPCState *env = &cpu->env;
102      struct boot_info *bi = env->load_info;
103  
104      cpu_reset(CPU(cpu));
105      /* Linux Kernel Parameters (passing device tree):
106         *   r3: pointer to the fdt
107         *   r4: 0
108         *   r5: 0
109         *   r6: epapr magic
110         *   r7: size of IMA in bytes
111         *   r8: 0
112         *   r9: 0
113      */
114      env->gpr[1] = (16 * MiB) - 8;
115      /* Provide a device-tree.  */
116      env->gpr[3] = bi->fdt;
117      env->nip = bi->bootstrap_pc;
118  
119      /* Create a mapping spanning the 32bit addr space. */
120      booke_set_tlb(&env->tlb.tlbe[0], 0, 0, 1U << 31);
121      booke_set_tlb(&env->tlb.tlbe[1], 0x80000000, 0x80000000, 1U << 31);
122      env->gpr[6] = tswap32(EPAPR_MAGIC);
123      env->gpr[7] = bi->ima_size;
124  }
125  
126  #define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb"
xilinx_load_device_tree(MachineState * machine,hwaddr addr,hwaddr initrd_base,hwaddr initrd_size)127  static int xilinx_load_device_tree(MachineState *machine,
128                                     hwaddr addr,
129                                     hwaddr initrd_base,
130                                     hwaddr initrd_size)
131  {
132      char *path;
133      int fdt_size;
134      void *fdt = NULL;
135      int r;
136      const char *dtb_filename;
137  
138      dtb_filename = machine->dtb;
139      if (dtb_filename) {
140          fdt = load_device_tree(dtb_filename, &fdt_size);
141          if (!fdt) {
142              error_report("Error while loading device tree file '%s'",
143                  dtb_filename);
144          }
145      } else {
146          /* Try the local "ppc.dtb" override.  */
147          fdt = load_device_tree("ppc.dtb", &fdt_size);
148          if (!fdt) {
149              path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
150              if (path) {
151                  fdt = load_device_tree(path, &fdt_size);
152                  g_free(path);
153              }
154          }
155      }
156      if (!fdt) {
157          return 0;
158      }
159  
160      r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
161                                initrd_base);
162      if (r < 0) {
163          error_report("couldn't set /chosen/linux,initrd-start");
164      }
165  
166      r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
167                                (initrd_base + initrd_size));
168      if (r < 0) {
169          error_report("couldn't set /chosen/linux,initrd-end");
170      }
171  
172      r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
173                                  machine->kernel_cmdline);
174      if (r < 0)
175          fprintf(stderr, "couldn't set /chosen/bootargs\n");
176      cpu_physical_memory_write(addr, fdt, fdt_size);
177  
178      /* Set machine->fdt for 'dumpdtb' QMP/HMP command */
179      machine->fdt = fdt;
180  
181      return fdt_size;
182  }
183  
virtex_init(MachineState * machine)184  static void virtex_init(MachineState *machine)
185  {
186      const char *kernel_filename = machine->kernel_filename;
187      hwaddr initrd_base = 0;
188      int initrd_size = 0;
189      MemoryRegion *address_space_mem = get_system_memory();
190      DeviceState *dev;
191      PowerPCCPU *cpu;
192      CPUPPCState *env;
193      hwaddr ram_base = 0;
194      DriveInfo *dinfo;
195      qemu_irq irq[32], cpu_irq;
196      int kernel_size;
197      int i;
198  
199      /* init CPUs */
200      cpu = ppc440_init_xilinx(machine->cpu_type, 400000000);
201      env = &cpu->env;
202  
203      if (env->mmu_model != POWERPC_MMU_BOOKE) {
204          error_report("MMU model %i not supported by this machine",
205                       env->mmu_model);
206          exit(1);
207      }
208  
209      qemu_register_reset(main_cpu_reset, cpu);
210  
211      memory_region_add_subregion(address_space_mem, ram_base, machine->ram);
212  
213      dinfo = drive_get(IF_PFLASH, 0, 0);
214      pflash_cfi01_register(PFLASH_BASEADDR, "virtex.flash", FLASH_SIZE,
215                            dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
216                            64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1);
217  
218      cpu_irq = qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT);
219      dev = qdev_new("xlnx.xps-intc");
220      qdev_prop_set_uint32(dev, "kind-of-intr", 0);
221      sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
222      sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
223      sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq);
224      for (i = 0; i < 32; i++) {
225          irq[i] = qdev_get_gpio_in(dev, i);
226      }
227  
228      serial_mm_init(address_space_mem, UART16550_BASEADDR, 2, irq[UART16550_IRQ],
229                     115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
230  
231      /* 2 timers at irq 2 @ 62 Mhz.  */
232      dev = qdev_new("xlnx.xps-timer");
233      qdev_prop_set_uint32(dev, "one-timer-only", 0);
234      qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000);
235      sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
236      sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR);
237      sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
238  
239      if (kernel_filename) {
240          uint64_t entry, high;
241          hwaddr boot_offset;
242  
243          /* Boots a kernel elf binary.  */
244          kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
245                                 &entry, NULL, &high, NULL, 1, PPC_ELF_MACHINE,
246                                 0, 0);
247          boot_info.bootstrap_pc = entry & 0x00ffffff;
248  
249          if (kernel_size < 0) {
250              boot_offset = 0x1200000;
251              /* If we failed loading ELF's try a raw image.  */
252              kernel_size = load_image_targphys(kernel_filename,
253                                                boot_offset,
254                                                machine->ram_size);
255              boot_info.bootstrap_pc = boot_offset;
256              high = boot_info.bootstrap_pc + kernel_size + 8192;
257          }
258  
259          boot_info.ima_size = kernel_size;
260  
261          /* Load initrd. */
262          if (machine->initrd_filename) {
263              initrd_base = high = ROUND_UP(high, 4);
264              initrd_size = load_image_targphys(machine->initrd_filename,
265                                                high, machine->ram_size - high);
266  
267              if (initrd_size < 0) {
268                  error_report("couldn't load ram disk '%s'",
269                               machine->initrd_filename);
270                  exit(1);
271              }
272              high = ROUND_UP(high + initrd_size, 4);
273          }
274  
275          /* Provide a device-tree.  */
276          boot_info.fdt = high + (8192 * 2);
277          boot_info.fdt &= ~8191;
278  
279          xilinx_load_device_tree(machine, boot_info.fdt,
280                                  initrd_base, initrd_size);
281      }
282      env->load_info = &boot_info;
283  }
284  
virtex_machine_init(MachineClass * mc)285  static void virtex_machine_init(MachineClass *mc)
286  {
287      mc->desc = "Xilinx Virtex ML507 reference design";
288      mc->init = virtex_init;
289      mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("440-xilinx");
290      mc->default_ram_id = "ram";
291  }
292  
293  DEFINE_MACHINE("virtex-ml507", virtex_machine_init)
294