xref: /openbmc/qemu/hw/mips/malta.c (revision 08ae519ab8eb6c9abbd97156cb3678f372521501)
15298722eSAleksandar Markovic /*
25298722eSAleksandar Markovic  * QEMU Malta board support
35298722eSAleksandar Markovic  *
45298722eSAleksandar Markovic  * Copyright (c) 2006 Aurelien Jarno
55298722eSAleksandar Markovic  *
65298722eSAleksandar Markovic  * Permission is hereby granted, free of charge, to any person obtaining a copy
75298722eSAleksandar Markovic  * of this software and associated documentation files (the "Software"), to deal
85298722eSAleksandar Markovic  * in the Software without restriction, including without limitation the rights
95298722eSAleksandar Markovic  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
105298722eSAleksandar Markovic  * copies of the Software, and to permit persons to whom the Software is
115298722eSAleksandar Markovic  * furnished to do so, subject to the following conditions:
125298722eSAleksandar Markovic  *
135298722eSAleksandar Markovic  * The above copyright notice and this permission notice shall be included in
145298722eSAleksandar Markovic  * all copies or substantial portions of the Software.
155298722eSAleksandar Markovic  *
165298722eSAleksandar Markovic  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
175298722eSAleksandar Markovic  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
185298722eSAleksandar Markovic  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
195298722eSAleksandar Markovic  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
205298722eSAleksandar Markovic  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
215298722eSAleksandar Markovic  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
225298722eSAleksandar Markovic  * THE SOFTWARE.
235298722eSAleksandar Markovic  */
245298722eSAleksandar Markovic 
255298722eSAleksandar Markovic #include "qemu/osdep.h"
265298722eSAleksandar Markovic #include "qemu/units.h"
2707741e67SPhilippe Mathieu-Daudé #include "qemu/bitops.h"
282c65db5eSPaolo Bonzini #include "qemu/datadir.h"
293a8ff366SPhilippe Mathieu-Daudé #include "qemu/cutils.h"
306233a138SJason A. Donenfeld #include "qemu/guest-random.h"
31eea1f5baSPhilippe Mathieu-Daudé #include "hw/clock.h"
325298722eSAleksandar Markovic #include "hw/southbridge/piix.h"
335298722eSAleksandar Markovic #include "hw/isa/superio.h"
347e6b5497SBernhard Beschow #include "hw/char/serial-mm.h"
355298722eSAleksandar Markovic #include "net/net.h"
365298722eSAleksandar Markovic #include "hw/boards.h"
375298722eSAleksandar Markovic #include "hw/i2c/smbus_eeprom.h"
385298722eSAleksandar Markovic #include "hw/block/flash.h"
395298722eSAleksandar Markovic #include "hw/mips/mips.h"
40fe1f2f4eSJiaxun Yang #include "hw/mips/bootloader.h"
415298722eSAleksandar Markovic #include "hw/pci/pci.h"
423c73d590SBernhard Beschow #include "hw/pci/pci_bus.h"
435298722eSAleksandar Markovic #include "qemu/log.h"
44d240d3fbSBernhard Beschow #include "hw/ide/pci.h"
455298722eSAleksandar Markovic #include "hw/irq.h"
465298722eSAleksandar Markovic #include "hw/loader.h"
475298722eSAleksandar Markovic #include "elf.h"
48db1015e9SEduardo Habkost #include "qom/object.h"
495298722eSAleksandar Markovic #include "hw/sysbus.h"             /* SysBusDevice */
505298722eSAleksandar Markovic #include "qemu/host-utils.h"
515298722eSAleksandar Markovic #include "sysemu/qtest.h"
525298722eSAleksandar Markovic #include "sysemu/reset.h"
535298722eSAleksandar Markovic #include "sysemu/runstate.h"
545298722eSAleksandar Markovic #include "qapi/error.h"
555298722eSAleksandar Markovic #include "qemu/error-report.h"
565298722eSAleksandar Markovic #include "sysemu/kvm.h"
576b5fe137SPhilippe Mathieu-Daudé #include "semihosting/semihost.h"
585298722eSAleksandar Markovic #include "hw/mips/cps.h"
59eea1f5baSPhilippe Mathieu-Daudé #include "hw/qdev-clock.h"
60a8448735SPaolo Bonzini #include "target/mips/internal.h"
619f81e43fSPhilippe Mathieu-Daudé #include "trace.h"
621eb64c39SPhilippe Mathieu-Daudé #include "cpu.h"
635298722eSAleksandar Markovic 
64df055c65SJiaxun Yang #define ENVP_PADDR          0x2000
65df055c65SJiaxun Yang #define ENVP_VADDR          cpu_mips_phys_to_kseg0(NULL, ENVP_PADDR)
665298722eSAleksandar Markovic #define ENVP_NB_ENTRIES     16
675298722eSAleksandar Markovic #define ENVP_ENTRY_SIZE     256
685298722eSAleksandar Markovic 
695298722eSAleksandar Markovic /* Hardware addresses */
705298722eSAleksandar Markovic #define FLASH_ADDRESS       0x1e000000ULL
715298722eSAleksandar Markovic #define FPGA_ADDRESS        0x1f000000ULL
725298722eSAleksandar Markovic #define RESET_ADDRESS       0x1fc00000ULL
735298722eSAleksandar Markovic 
745298722eSAleksandar Markovic #define FLASH_SIZE          0x400000
751eb64c39SPhilippe Mathieu-Daudé #define BIOS_SIZE           (4 * MiB)
765298722eSAleksandar Markovic 
776dd92ce6SPhilippe Mathieu-Daudé #define PIIX4_PCI_DEVFN     PCI_DEVFN(10, 0)
786dd92ce6SPhilippe Mathieu-Daudé 
795298722eSAleksandar Markovic typedef struct {
805298722eSAleksandar Markovic     MemoryRegion iomem;
815298722eSAleksandar Markovic     MemoryRegion iomem_lo; /* 0 - 0x900 */
825298722eSAleksandar Markovic     MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */
835298722eSAleksandar Markovic     uint32_t leds;
845298722eSAleksandar Markovic     uint32_t brk;
855298722eSAleksandar Markovic     uint32_t gpout;
865298722eSAleksandar Markovic     uint32_t i2cin;
875298722eSAleksandar Markovic     uint32_t i2coe;
885298722eSAleksandar Markovic     uint32_t i2cout;
895298722eSAleksandar Markovic     uint32_t i2csel;
905298722eSAleksandar Markovic     CharBackend display;
915298722eSAleksandar Markovic     char display_text[9];
925298722eSAleksandar Markovic     SerialMM *uart;
935298722eSAleksandar Markovic     bool display_inited;
945298722eSAleksandar Markovic } MaltaFPGAState;
955298722eSAleksandar Markovic 
961eb64c39SPhilippe Mathieu-Daudé #if TARGET_BIG_ENDIAN
971eb64c39SPhilippe Mathieu-Daudé #define BIOS_FILENAME "mips_bios.bin"
981eb64c39SPhilippe Mathieu-Daudé #else
991eb64c39SPhilippe Mathieu-Daudé #define BIOS_FILENAME "mipsel_bios.bin"
1001eb64c39SPhilippe Mathieu-Daudé #endif
1011eb64c39SPhilippe Mathieu-Daudé 
1025298722eSAleksandar Markovic #define TYPE_MIPS_MALTA "mips-malta"
1038063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(MaltaState, MIPS_MALTA)
1045298722eSAleksandar Markovic 
105db1015e9SEduardo Habkost struct MaltaState {
1065298722eSAleksandar Markovic     SysBusDevice parent_obj;
1075298722eSAleksandar Markovic 
108eea1f5baSPhilippe Mathieu-Daudé     Clock *cpuclk;
1095298722eSAleksandar Markovic     MIPSCPSState cps;
110db1015e9SEduardo Habkost };
1115298722eSAleksandar Markovic 
1125298722eSAleksandar Markovic static struct _loaderparams {
1135298722eSAleksandar Markovic     int ram_size, ram_low_size;
1145298722eSAleksandar Markovic     const char *kernel_filename;
1155298722eSAleksandar Markovic     const char *kernel_cmdline;
1165298722eSAleksandar Markovic     const char *initrd_filename;
1175298722eSAleksandar Markovic } loaderparams;
1185298722eSAleksandar Markovic 
1195298722eSAleksandar Markovic /* Malta FPGA */
malta_fpga_update_display_leds(MaltaFPGAState * s)120e7a65ba6SPhilippe Mathieu-Daudé static void malta_fpga_update_display_leds(MaltaFPGAState *s)
1215298722eSAleksandar Markovic {
1225298722eSAleksandar Markovic     char leds_text[9];
1235298722eSAleksandar Markovic     int i;
1245298722eSAleksandar Markovic 
1255298722eSAleksandar Markovic     for (i = 7 ; i >= 0 ; i--) {
1265298722eSAleksandar Markovic         if (s->leds & (1 << i)) {
1275298722eSAleksandar Markovic             leds_text[i] = '#';
1285298722eSAleksandar Markovic         } else {
1295298722eSAleksandar Markovic             leds_text[i] = ' ';
1305298722eSAleksandar Markovic         }
1315298722eSAleksandar Markovic     }
1325298722eSAleksandar Markovic     leds_text[8] = '\0';
1335298722eSAleksandar Markovic 
1349f81e43fSPhilippe Mathieu-Daudé     trace_malta_fpga_leds(leds_text);
1355298722eSAleksandar Markovic     qemu_chr_fe_printf(&s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n",
1365298722eSAleksandar Markovic                        leds_text);
137e7a65ba6SPhilippe Mathieu-Daudé }
138e7a65ba6SPhilippe Mathieu-Daudé 
malta_fpga_update_display_ascii(MaltaFPGAState * s)139e7a65ba6SPhilippe Mathieu-Daudé static void malta_fpga_update_display_ascii(MaltaFPGAState *s)
140e7a65ba6SPhilippe Mathieu-Daudé {
1419f81e43fSPhilippe Mathieu-Daudé     trace_malta_fpga_display(s->display_text);
1425298722eSAleksandar Markovic     qemu_chr_fe_printf(&s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|",
1435298722eSAleksandar Markovic                        s->display_text);
1445298722eSAleksandar Markovic }
1455298722eSAleksandar Markovic 
1465298722eSAleksandar Markovic /*
1475298722eSAleksandar Markovic  * EEPROM 24C01 / 24C02 emulation.
1485298722eSAleksandar Markovic  *
1495298722eSAleksandar Markovic  * Emulation for serial EEPROMs:
1505298722eSAleksandar Markovic  * 24C01 - 1024 bit (128 x 8)
1515298722eSAleksandar Markovic  * 24C02 - 2048 bit (256 x 8)
1525298722eSAleksandar Markovic  *
1535298722eSAleksandar Markovic  * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
1545298722eSAleksandar Markovic  */
1555298722eSAleksandar Markovic 
1565298722eSAleksandar Markovic #if defined(DEBUG)
1575298722eSAleksandar Markovic #  define logout(fmt, ...) \
1585298722eSAleksandar Markovic           fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ## __VA_ARGS__)
1595298722eSAleksandar Markovic #else
1605298722eSAleksandar Markovic #  define logout(fmt, ...) ((void)0)
1615298722eSAleksandar Markovic #endif
1625298722eSAleksandar Markovic 
1635298722eSAleksandar Markovic struct _eeprom24c0x_t {
1645298722eSAleksandar Markovic   uint8_t tick;
1655298722eSAleksandar Markovic   uint8_t address;
1665298722eSAleksandar Markovic   uint8_t command;
1675298722eSAleksandar Markovic   uint8_t ack;
1685298722eSAleksandar Markovic   uint8_t scl;
1695298722eSAleksandar Markovic   uint8_t sda;
1705298722eSAleksandar Markovic   uint8_t data;
1715298722eSAleksandar Markovic   /* uint16_t size; */
1725298722eSAleksandar Markovic   uint8_t contents[256];
1735298722eSAleksandar Markovic };
1745298722eSAleksandar Markovic 
1755298722eSAleksandar Markovic typedef struct _eeprom24c0x_t eeprom24c0x_t;
1765298722eSAleksandar Markovic 
1775298722eSAleksandar Markovic static eeprom24c0x_t spd_eeprom = {
1785298722eSAleksandar Markovic     .contents = {
1795298722eSAleksandar Markovic         /* 00000000: */
1805298722eSAleksandar Markovic         0x80, 0x08, 0xFF, 0x0D, 0x0A, 0xFF, 0x40, 0x00,
1815298722eSAleksandar Markovic         /* 00000008: */
1825298722eSAleksandar Markovic         0x01, 0x75, 0x54, 0x00, 0x82, 0x08, 0x00, 0x01,
1835298722eSAleksandar Markovic         /* 00000010: */
1845298722eSAleksandar Markovic         0x8F, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
1855298722eSAleksandar Markovic         /* 00000018: */
1865298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x14, 0x0F, 0x14, 0x2D, 0xFF,
1875298722eSAleksandar Markovic         /* 00000020: */
1885298722eSAleksandar Markovic         0x15, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00,
1895298722eSAleksandar Markovic         /* 00000028: */
1905298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1915298722eSAleksandar Markovic         /* 00000030: */
1925298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1935298722eSAleksandar Markovic         /* 00000038: */
1945298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xD0,
1955298722eSAleksandar Markovic         /* 00000040: */
1965298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1975298722eSAleksandar Markovic         /* 00000048: */
1985298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1995298722eSAleksandar Markovic         /* 00000050: */
2005298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2015298722eSAleksandar Markovic         /* 00000058: */
2025298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2035298722eSAleksandar Markovic         /* 00000060: */
2045298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2055298722eSAleksandar Markovic         /* 00000068: */
2065298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2075298722eSAleksandar Markovic         /* 00000070: */
2085298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2095298722eSAleksandar Markovic         /* 00000078: */
2105298722eSAleksandar Markovic         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xF4,
2115298722eSAleksandar Markovic     },
2125298722eSAleksandar Markovic };
2135298722eSAleksandar Markovic 
generate_eeprom_spd(uint8_t * eeprom,ram_addr_t ram_size)2145298722eSAleksandar Markovic static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
2155298722eSAleksandar Markovic {
2169ce8c6ddSPhilippe Mathieu-Daudé     enum sdram_type type;
2175298722eSAleksandar Markovic     uint8_t *spd = spd_eeprom.contents;
2185298722eSAleksandar Markovic     uint8_t nbanks = 0;
2195298722eSAleksandar Markovic     uint16_t density = 0;
2205298722eSAleksandar Markovic     int i;
2215298722eSAleksandar Markovic 
2225298722eSAleksandar Markovic     /* work in terms of MB */
2235298722eSAleksandar Markovic     ram_size /= MiB;
2245298722eSAleksandar Markovic 
2255298722eSAleksandar Markovic     while ((ram_size >= 4) && (nbanks <= 2)) {
2265298722eSAleksandar Markovic         int sz_log2 = MIN(31 - clz32(ram_size), 14);
2275298722eSAleksandar Markovic         nbanks++;
2285298722eSAleksandar Markovic         density |= 1 << (sz_log2 - 2);
2295298722eSAleksandar Markovic         ram_size -= 1 << sz_log2;
2305298722eSAleksandar Markovic     }
2315298722eSAleksandar Markovic 
2325298722eSAleksandar Markovic     /* split to 2 banks if possible */
2335298722eSAleksandar Markovic     if ((nbanks == 1) && (density > 1)) {
2345298722eSAleksandar Markovic         nbanks++;
2355298722eSAleksandar Markovic         density >>= 1;
2365298722eSAleksandar Markovic     }
2375298722eSAleksandar Markovic 
2385298722eSAleksandar Markovic     if (density & 0xff00) {
2395298722eSAleksandar Markovic         density = (density & 0xe0) | ((density >> 8) & 0x1f);
2405298722eSAleksandar Markovic         type = DDR2;
2415298722eSAleksandar Markovic     } else if (!(density & 0x1f)) {
2425298722eSAleksandar Markovic         type = DDR2;
2435298722eSAleksandar Markovic     } else {
2445298722eSAleksandar Markovic         type = SDR;
2455298722eSAleksandar Markovic     }
2465298722eSAleksandar Markovic 
2475298722eSAleksandar Markovic     if (ram_size) {
2485298722eSAleksandar Markovic         warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB"
2495298722eSAleksandar Markovic                     " of SDRAM", ram_size);
2505298722eSAleksandar Markovic     }
2515298722eSAleksandar Markovic 
2525298722eSAleksandar Markovic     /* fill in SPD memory information */
2535298722eSAleksandar Markovic     spd[2] = type;
2545298722eSAleksandar Markovic     spd[5] = nbanks;
2555298722eSAleksandar Markovic     spd[31] = density;
2565298722eSAleksandar Markovic 
2575298722eSAleksandar Markovic     /* checksum */
2585298722eSAleksandar Markovic     spd[63] = 0;
2595298722eSAleksandar Markovic     for (i = 0; i < 63; i++) {
2605298722eSAleksandar Markovic         spd[63] += spd[i];
2615298722eSAleksandar Markovic     }
2625298722eSAleksandar Markovic 
2635298722eSAleksandar Markovic     /* copy for SMBUS */
2645298722eSAleksandar Markovic     memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
2655298722eSAleksandar Markovic }
2665298722eSAleksandar Markovic 
generate_eeprom_serial(uint8_t * eeprom)2675298722eSAleksandar Markovic static void generate_eeprom_serial(uint8_t *eeprom)
2685298722eSAleksandar Markovic {
2695298722eSAleksandar Markovic     int i, pos = 0;
2705298722eSAleksandar Markovic     uint8_t mac[6] = { 0x00 };
2715298722eSAleksandar Markovic     uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
2725298722eSAleksandar Markovic 
2735298722eSAleksandar Markovic     /* version */
2745298722eSAleksandar Markovic     eeprom[pos++] = 0x01;
2755298722eSAleksandar Markovic 
2765298722eSAleksandar Markovic     /* count */
2775298722eSAleksandar Markovic     eeprom[pos++] = 0x02;
2785298722eSAleksandar Markovic 
2795298722eSAleksandar Markovic     /* MAC address */
2805298722eSAleksandar Markovic     eeprom[pos++] = 0x01; /* MAC */
2815298722eSAleksandar Markovic     eeprom[pos++] = 0x06; /* length */
2825298722eSAleksandar Markovic     memcpy(&eeprom[pos], mac, sizeof(mac));
2835298722eSAleksandar Markovic     pos += sizeof(mac);
2845298722eSAleksandar Markovic 
2855298722eSAleksandar Markovic     /* serial number */
2865298722eSAleksandar Markovic     eeprom[pos++] = 0x02; /* serial */
2875298722eSAleksandar Markovic     eeprom[pos++] = 0x05; /* length */
2885298722eSAleksandar Markovic     memcpy(&eeprom[pos], sn, sizeof(sn));
2895298722eSAleksandar Markovic     pos += sizeof(sn);
2905298722eSAleksandar Markovic 
2915298722eSAleksandar Markovic     /* checksum */
2925298722eSAleksandar Markovic     eeprom[pos] = 0;
2935298722eSAleksandar Markovic     for (i = 0; i < pos; i++) {
2945298722eSAleksandar Markovic         eeprom[pos] += eeprom[i];
2955298722eSAleksandar Markovic     }
2965298722eSAleksandar Markovic }
2975298722eSAleksandar Markovic 
eeprom24c0x_read(eeprom24c0x_t * eeprom)2985298722eSAleksandar Markovic static uint8_t eeprom24c0x_read(eeprom24c0x_t *eeprom)
2995298722eSAleksandar Markovic {
3005298722eSAleksandar Markovic     logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
3015298722eSAleksandar Markovic         eeprom->tick, eeprom->scl, eeprom->sda, eeprom->data);
3025298722eSAleksandar Markovic     return eeprom->sda;
3035298722eSAleksandar Markovic }
3045298722eSAleksandar Markovic 
eeprom24c0x_write(eeprom24c0x_t * eeprom,int scl,int sda)3055298722eSAleksandar Markovic static void eeprom24c0x_write(eeprom24c0x_t *eeprom, int scl, int sda)
3065298722eSAleksandar Markovic {
3075298722eSAleksandar Markovic     if (eeprom->scl && scl && (eeprom->sda != sda)) {
3085298722eSAleksandar Markovic         logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
3095298722eSAleksandar Markovic                 eeprom->tick, eeprom->scl, scl, eeprom->sda, sda,
3105298722eSAleksandar Markovic                 sda ? "stop" : "start");
3115298722eSAleksandar Markovic         if (!sda) {
3125298722eSAleksandar Markovic             eeprom->tick = 1;
3135298722eSAleksandar Markovic             eeprom->command = 0;
3145298722eSAleksandar Markovic         }
3155298722eSAleksandar Markovic     } else if (eeprom->tick == 0 && !eeprom->ack) {
3165298722eSAleksandar Markovic         /* Waiting for start. */
3175298722eSAleksandar Markovic         logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
3185298722eSAleksandar Markovic                 eeprom->tick, eeprom->scl, scl, eeprom->sda, sda);
3195298722eSAleksandar Markovic     } else if (!eeprom->scl && scl) {
3205298722eSAleksandar Markovic         logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
3215298722eSAleksandar Markovic                 eeprom->tick, eeprom->scl, scl, eeprom->sda, sda);
3225298722eSAleksandar Markovic         if (eeprom->ack) {
3235298722eSAleksandar Markovic             logout("\ti2c ack bit = 0\n");
3245298722eSAleksandar Markovic             sda = 0;
3255298722eSAleksandar Markovic             eeprom->ack = 0;
3265298722eSAleksandar Markovic         } else if (eeprom->sda == sda) {
3275298722eSAleksandar Markovic             uint8_t bit = (sda != 0);
3285298722eSAleksandar Markovic             logout("\ti2c bit = %d\n", bit);
3295298722eSAleksandar Markovic             if (eeprom->tick < 9) {
3305298722eSAleksandar Markovic                 eeprom->command <<= 1;
3315298722eSAleksandar Markovic                 eeprom->command += bit;
3325298722eSAleksandar Markovic                 eeprom->tick++;
3335298722eSAleksandar Markovic                 if (eeprom->tick == 9) {
3345298722eSAleksandar Markovic                     logout("\tcommand 0x%04x, %s\n", eeprom->command,
3355298722eSAleksandar Markovic                            bit ? "read" : "write");
3365298722eSAleksandar Markovic                     eeprom->ack = 1;
3375298722eSAleksandar Markovic                 }
3385298722eSAleksandar Markovic             } else if (eeprom->tick < 17) {
3395298722eSAleksandar Markovic                 if (eeprom->command & 1) {
3405298722eSAleksandar Markovic                     sda = ((eeprom->data & 0x80) != 0);
3415298722eSAleksandar Markovic                 }
3425298722eSAleksandar Markovic                 eeprom->address <<= 1;
3435298722eSAleksandar Markovic                 eeprom->address += bit;
3445298722eSAleksandar Markovic                 eeprom->tick++;
3455298722eSAleksandar Markovic                 eeprom->data <<= 1;
3465298722eSAleksandar Markovic                 if (eeprom->tick == 17) {
3475298722eSAleksandar Markovic                     eeprom->data = eeprom->contents[eeprom->address];
3485298722eSAleksandar Markovic                     logout("\taddress 0x%04x, data 0x%02x\n",
3495298722eSAleksandar Markovic                            eeprom->address, eeprom->data);
3505298722eSAleksandar Markovic                     eeprom->ack = 1;
3515298722eSAleksandar Markovic                     eeprom->tick = 0;
3525298722eSAleksandar Markovic                 }
3535298722eSAleksandar Markovic             } else if (eeprom->tick >= 17) {
3545298722eSAleksandar Markovic                 sda = 0;
3555298722eSAleksandar Markovic             }
3565298722eSAleksandar Markovic         } else {
3575298722eSAleksandar Markovic             logout("\tsda changed with raising scl\n");
3585298722eSAleksandar Markovic         }
3595298722eSAleksandar Markovic     } else {
3605298722eSAleksandar Markovic         logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom->tick, eeprom->scl,
3615298722eSAleksandar Markovic                scl, eeprom->sda, sda);
3625298722eSAleksandar Markovic     }
3635298722eSAleksandar Markovic     eeprom->scl = scl;
3645298722eSAleksandar Markovic     eeprom->sda = sda;
3655298722eSAleksandar Markovic }
3665298722eSAleksandar Markovic 
malta_fpga_read(void * opaque,hwaddr addr,unsigned size)3675298722eSAleksandar Markovic static uint64_t malta_fpga_read(void *opaque, hwaddr addr,
3685298722eSAleksandar Markovic                                 unsigned size)
3695298722eSAleksandar Markovic {
3705298722eSAleksandar Markovic     MaltaFPGAState *s = opaque;
3715298722eSAleksandar Markovic     uint32_t val = 0;
3725298722eSAleksandar Markovic     uint32_t saddr;
3735298722eSAleksandar Markovic 
3745298722eSAleksandar Markovic     saddr = (addr & 0xfffff);
3755298722eSAleksandar Markovic 
3765298722eSAleksandar Markovic     switch (saddr) {
3775298722eSAleksandar Markovic 
3785298722eSAleksandar Markovic     /* SWITCH Register */
3795298722eSAleksandar Markovic     case 0x00200:
3805298722eSAleksandar Markovic         val = 0x00000000;
3815298722eSAleksandar Markovic         break;
3825298722eSAleksandar Markovic 
3835298722eSAleksandar Markovic     /* STATUS Register */
3845298722eSAleksandar Markovic     case 0x00208:
385ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
3865298722eSAleksandar Markovic         val = 0x00000012;
3875298722eSAleksandar Markovic #else
3885298722eSAleksandar Markovic         val = 0x00000010;
3895298722eSAleksandar Markovic #endif
3905298722eSAleksandar Markovic         break;
3915298722eSAleksandar Markovic 
3925298722eSAleksandar Markovic     /* JMPRS Register */
3935298722eSAleksandar Markovic     case 0x00210:
3945298722eSAleksandar Markovic         val = 0x00;
3955298722eSAleksandar Markovic         break;
3965298722eSAleksandar Markovic 
3975298722eSAleksandar Markovic     /* LEDBAR Register */
3985298722eSAleksandar Markovic     case 0x00408:
3995298722eSAleksandar Markovic         val = s->leds;
4005298722eSAleksandar Markovic         break;
4015298722eSAleksandar Markovic 
4025298722eSAleksandar Markovic     /* BRKRES Register */
4035298722eSAleksandar Markovic     case 0x00508:
4045298722eSAleksandar Markovic         val = s->brk;
4055298722eSAleksandar Markovic         break;
4065298722eSAleksandar Markovic 
4075298722eSAleksandar Markovic     /* UART Registers are handled directly by the serial device */
4085298722eSAleksandar Markovic 
4095298722eSAleksandar Markovic     /* GPOUT Register */
4105298722eSAleksandar Markovic     case 0x00a00:
4115298722eSAleksandar Markovic         val = s->gpout;
4125298722eSAleksandar Markovic         break;
4135298722eSAleksandar Markovic 
4145298722eSAleksandar Markovic     /* XXX: implement a real I2C controller */
4155298722eSAleksandar Markovic 
4165298722eSAleksandar Markovic     /* GPINP Register */
4175298722eSAleksandar Markovic     case 0x00a08:
4185298722eSAleksandar Markovic         /* IN = OUT until a real I2C control is implemented */
4195298722eSAleksandar Markovic         if (s->i2csel) {
4205298722eSAleksandar Markovic             val = s->i2cout;
4215298722eSAleksandar Markovic         } else {
4225298722eSAleksandar Markovic             val = 0x00;
4235298722eSAleksandar Markovic         }
4245298722eSAleksandar Markovic         break;
4255298722eSAleksandar Markovic 
4265298722eSAleksandar Markovic     /* I2CINP Register */
4275298722eSAleksandar Markovic     case 0x00b00:
4285298722eSAleksandar Markovic         val = ((s->i2cin & ~1) | eeprom24c0x_read(&spd_eeprom));
4295298722eSAleksandar Markovic         break;
4305298722eSAleksandar Markovic 
4315298722eSAleksandar Markovic     /* I2COE Register */
4325298722eSAleksandar Markovic     case 0x00b08:
4335298722eSAleksandar Markovic         val = s->i2coe;
4345298722eSAleksandar Markovic         break;
4355298722eSAleksandar Markovic 
4365298722eSAleksandar Markovic     /* I2COUT Register */
4375298722eSAleksandar Markovic     case 0x00b10:
4385298722eSAleksandar Markovic         val = s->i2cout;
4395298722eSAleksandar Markovic         break;
4405298722eSAleksandar Markovic 
4415298722eSAleksandar Markovic     /* I2CSEL Register */
4425298722eSAleksandar Markovic     case 0x00b18:
4435298722eSAleksandar Markovic         val = s->i2csel;
4445298722eSAleksandar Markovic         break;
4455298722eSAleksandar Markovic 
4465298722eSAleksandar Markovic     default:
447c707f06fSAleksandar Markovic         qemu_log_mask(LOG_GUEST_ERROR,
448c707f06fSAleksandar Markovic                       "malta_fpga_read: Bad register addr 0x%"HWADDR_PRIX"\n",
4495298722eSAleksandar Markovic                       addr);
4505298722eSAleksandar Markovic         break;
4515298722eSAleksandar Markovic     }
4525298722eSAleksandar Markovic     return val;
4535298722eSAleksandar Markovic }
4545298722eSAleksandar Markovic 
malta_fpga_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)4555298722eSAleksandar Markovic static void malta_fpga_write(void *opaque, hwaddr addr,
4565298722eSAleksandar Markovic                              uint64_t val, unsigned size)
4575298722eSAleksandar Markovic {
4585298722eSAleksandar Markovic     MaltaFPGAState *s = opaque;
4595298722eSAleksandar Markovic     uint32_t saddr;
4605298722eSAleksandar Markovic 
4615298722eSAleksandar Markovic     saddr = (addr & 0xfffff);
4625298722eSAleksandar Markovic 
4635298722eSAleksandar Markovic     switch (saddr) {
4645298722eSAleksandar Markovic 
4655298722eSAleksandar Markovic     /* SWITCH Register */
4665298722eSAleksandar Markovic     case 0x00200:
4675298722eSAleksandar Markovic         break;
4685298722eSAleksandar Markovic 
4695298722eSAleksandar Markovic     /* JMPRS Register */
4705298722eSAleksandar Markovic     case 0x00210:
4715298722eSAleksandar Markovic         break;
4725298722eSAleksandar Markovic 
4735298722eSAleksandar Markovic     /* LEDBAR Register */
4745298722eSAleksandar Markovic     case 0x00408:
4755298722eSAleksandar Markovic         s->leds = val & 0xff;
476e7a65ba6SPhilippe Mathieu-Daudé         malta_fpga_update_display_leds(s);
4775298722eSAleksandar Markovic         break;
4785298722eSAleksandar Markovic 
4795298722eSAleksandar Markovic     /* ASCIIWORD Register */
4805298722eSAleksandar Markovic     case 0x00410:
4815298722eSAleksandar Markovic         snprintf(s->display_text, 9, "%08X", (uint32_t)val);
482e7a65ba6SPhilippe Mathieu-Daudé         malta_fpga_update_display_ascii(s);
4835298722eSAleksandar Markovic         break;
4845298722eSAleksandar Markovic 
4855298722eSAleksandar Markovic     /* ASCIIPOS0 to ASCIIPOS7 Registers */
4865298722eSAleksandar Markovic     case 0x00418:
4875298722eSAleksandar Markovic     case 0x00420:
4885298722eSAleksandar Markovic     case 0x00428:
4895298722eSAleksandar Markovic     case 0x00430:
4905298722eSAleksandar Markovic     case 0x00438:
4915298722eSAleksandar Markovic     case 0x00440:
4925298722eSAleksandar Markovic     case 0x00448:
4935298722eSAleksandar Markovic     case 0x00450:
4945298722eSAleksandar Markovic         s->display_text[(saddr - 0x00418) >> 3] = (char) val;
495e7a65ba6SPhilippe Mathieu-Daudé         malta_fpga_update_display_ascii(s);
4965298722eSAleksandar Markovic         break;
4975298722eSAleksandar Markovic 
4985298722eSAleksandar Markovic     /* SOFTRES Register */
4995298722eSAleksandar Markovic     case 0x00500:
5005298722eSAleksandar Markovic         if (val == 0x42) {
5015298722eSAleksandar Markovic             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
5025298722eSAleksandar Markovic         }
5035298722eSAleksandar Markovic         break;
5045298722eSAleksandar Markovic 
5055298722eSAleksandar Markovic     /* BRKRES Register */
5065298722eSAleksandar Markovic     case 0x00508:
5075298722eSAleksandar Markovic         s->brk = val & 0xff;
5085298722eSAleksandar Markovic         break;
5095298722eSAleksandar Markovic 
5105298722eSAleksandar Markovic     /* UART Registers are handled directly by the serial device */
5115298722eSAleksandar Markovic 
5125298722eSAleksandar Markovic     /* GPOUT Register */
5135298722eSAleksandar Markovic     case 0x00a00:
5145298722eSAleksandar Markovic         s->gpout = val & 0xff;
5155298722eSAleksandar Markovic         break;
5165298722eSAleksandar Markovic 
5175298722eSAleksandar Markovic     /* I2COE Register */
5185298722eSAleksandar Markovic     case 0x00b08:
5195298722eSAleksandar Markovic         s->i2coe = val & 0x03;
5205298722eSAleksandar Markovic         break;
5215298722eSAleksandar Markovic 
5225298722eSAleksandar Markovic     /* I2COUT Register */
5235298722eSAleksandar Markovic     case 0x00b10:
5245298722eSAleksandar Markovic         eeprom24c0x_write(&spd_eeprom, val & 0x02, val & 0x01);
5255298722eSAleksandar Markovic         s->i2cout = val;
5265298722eSAleksandar Markovic         break;
5275298722eSAleksandar Markovic 
5285298722eSAleksandar Markovic     /* I2CSEL Register */
5295298722eSAleksandar Markovic     case 0x00b18:
5305298722eSAleksandar Markovic         s->i2csel = val & 0x01;
5315298722eSAleksandar Markovic         break;
5325298722eSAleksandar Markovic 
5335298722eSAleksandar Markovic     default:
534c707f06fSAleksandar Markovic         qemu_log_mask(LOG_GUEST_ERROR,
535c707f06fSAleksandar Markovic                       "malta_fpga_write: Bad register addr 0x%"HWADDR_PRIX"\n",
5365298722eSAleksandar Markovic                       addr);
5375298722eSAleksandar Markovic         break;
5385298722eSAleksandar Markovic     }
5395298722eSAleksandar Markovic }
5405298722eSAleksandar Markovic 
5415298722eSAleksandar Markovic static const MemoryRegionOps malta_fpga_ops = {
5425298722eSAleksandar Markovic     .read = malta_fpga_read,
5435298722eSAleksandar Markovic     .write = malta_fpga_write,
5445298722eSAleksandar Markovic     .endianness = DEVICE_NATIVE_ENDIAN,
5455298722eSAleksandar Markovic };
5465298722eSAleksandar Markovic 
malta_fpga_reset(void * opaque)5475298722eSAleksandar Markovic static void malta_fpga_reset(void *opaque)
5485298722eSAleksandar Markovic {
5495298722eSAleksandar Markovic     MaltaFPGAState *s = opaque;
5505298722eSAleksandar Markovic 
5515298722eSAleksandar Markovic     s->leds   = 0x00;
5525298722eSAleksandar Markovic     s->brk    = 0x0a;
5535298722eSAleksandar Markovic     s->gpout  = 0x00;
5545298722eSAleksandar Markovic     s->i2cin  = 0x3;
5555298722eSAleksandar Markovic     s->i2coe  = 0x0;
5565298722eSAleksandar Markovic     s->i2cout = 0x3;
5575298722eSAleksandar Markovic     s->i2csel = 0x1;
5585298722eSAleksandar Markovic 
5595298722eSAleksandar Markovic     s->display_text[8] = '\0';
5605298722eSAleksandar Markovic     snprintf(s->display_text, 9, "        ");
5615298722eSAleksandar Markovic }
5625298722eSAleksandar Markovic 
malta_fgpa_display_event(void * opaque,QEMUChrEvent event)5635298722eSAleksandar Markovic static void malta_fgpa_display_event(void *opaque, QEMUChrEvent event)
5645298722eSAleksandar Markovic {
5655298722eSAleksandar Markovic     MaltaFPGAState *s = opaque;
5665298722eSAleksandar Markovic 
5675298722eSAleksandar Markovic     if (event == CHR_EVENT_OPENED && !s->display_inited) {
5685298722eSAleksandar Markovic         qemu_chr_fe_printf(&s->display, "\e[HMalta LEDBAR\r\n");
5695298722eSAleksandar Markovic         qemu_chr_fe_printf(&s->display, "+--------+\r\n");
5705298722eSAleksandar Markovic         qemu_chr_fe_printf(&s->display, "+        +\r\n");
5715298722eSAleksandar Markovic         qemu_chr_fe_printf(&s->display, "+--------+\r\n");
5725298722eSAleksandar Markovic         qemu_chr_fe_printf(&s->display, "\n");
5735298722eSAleksandar Markovic         qemu_chr_fe_printf(&s->display, "Malta ASCII\r\n");
5745298722eSAleksandar Markovic         qemu_chr_fe_printf(&s->display, "+--------+\r\n");
5755298722eSAleksandar Markovic         qemu_chr_fe_printf(&s->display, "+        +\r\n");
5765298722eSAleksandar Markovic         qemu_chr_fe_printf(&s->display, "+--------+\r\n");
5775298722eSAleksandar Markovic         s->display_inited = true;
5785298722eSAleksandar Markovic     }
5795298722eSAleksandar Markovic }
5805298722eSAleksandar Markovic 
malta_fpga_init(MemoryRegion * address_space,hwaddr base,qemu_irq uart_irq,Chardev * uart_chr)5815298722eSAleksandar Markovic static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
5825298722eSAleksandar Markovic          hwaddr base, qemu_irq uart_irq, Chardev *uart_chr)
5835298722eSAleksandar Markovic {
5845298722eSAleksandar Markovic     MaltaFPGAState *s;
5855298722eSAleksandar Markovic     Chardev *chr;
5865298722eSAleksandar Markovic 
5875298722eSAleksandar Markovic     s = g_new0(MaltaFPGAState, 1);
5885298722eSAleksandar Markovic 
5895298722eSAleksandar Markovic     memory_region_init_io(&s->iomem, NULL, &malta_fpga_ops, s,
5905298722eSAleksandar Markovic                           "malta-fpga", 0x100000);
5915298722eSAleksandar Markovic     memory_region_init_alias(&s->iomem_lo, NULL, "malta-fpga",
5925298722eSAleksandar Markovic                              &s->iomem, 0, 0x900);
5935298722eSAleksandar Markovic     memory_region_init_alias(&s->iomem_hi, NULL, "malta-fpga",
5949a2133f4SPhilippe Mathieu-Daudé                              &s->iomem, 0xa00, 0x100000 - 0xa00);
5955298722eSAleksandar Markovic 
5965298722eSAleksandar Markovic     memory_region_add_subregion(address_space, base, &s->iomem_lo);
5975298722eSAleksandar Markovic     memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
5985298722eSAleksandar Markovic 
5995298722eSAleksandar Markovic     chr = qemu_chr_new("fpga", "vc:320x200", NULL);
6005298722eSAleksandar Markovic     qemu_chr_fe_init(&s->display, chr, NULL);
6015298722eSAleksandar Markovic     qemu_chr_fe_set_handlers(&s->display, NULL, NULL,
6025298722eSAleksandar Markovic                              malta_fgpa_display_event, NULL, s, NULL, true);
6035298722eSAleksandar Markovic 
6045298722eSAleksandar Markovic     s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
6055298722eSAleksandar Markovic                              230400, uart_chr, DEVICE_NATIVE_ENDIAN);
6065298722eSAleksandar Markovic 
6075298722eSAleksandar Markovic     malta_fpga_reset(s);
6085298722eSAleksandar Markovic     qemu_register_reset(malta_fpga_reset, s);
6095298722eSAleksandar Markovic 
6105298722eSAleksandar Markovic     return s;
6115298722eSAleksandar Markovic }
6125298722eSAleksandar Markovic 
6135298722eSAleksandar Markovic /* Network support */
network_init(PCIBus * pci_bus)6145298722eSAleksandar Markovic static void network_init(PCIBus *pci_bus)
6155298722eSAleksandar Markovic {
6165298722eSAleksandar Markovic     /* The malta board has a PCNet card using PCI SLOT 11 */
61776188401SDavid Woodhouse     pci_init_nic_in_slot(pci_bus, "pcnet", NULL, "0b");
61876188401SDavid Woodhouse     pci_init_nic_devices(pci_bus, "pcnet");
6195298722eSAleksandar Markovic }
6205298722eSAleksandar Markovic 
bl_setup_gt64120_jump_kernel(void ** p,uint64_t run_addr,uint64_t kernel_entry)6210e45355cSPhilippe Mathieu-Daudé static void bl_setup_gt64120_jump_kernel(void **p, uint64_t run_addr,
6220e45355cSPhilippe Mathieu-Daudé                                          uint64_t kernel_entry)
6230e45355cSPhilippe Mathieu-Daudé {
6241953dfa8SPhilippe Mathieu-Daudé     static const char pci_pins_cfg[PCI_NUM_PINS] = {
6251953dfa8SPhilippe Mathieu-Daudé         10, 10, 11, 11 /* PIIX IRQRC[A:D] */
6261953dfa8SPhilippe Mathieu-Daudé     };
6271953dfa8SPhilippe Mathieu-Daudé 
628d5c9fa47SMichael Tokarev     /* Bus endianness is always reversed */
6290e45355cSPhilippe Mathieu-Daudé #if TARGET_BIG_ENDIAN
630dc96009aSThomas Huth #define cpu_to_gt32(x) (x)
6310e45355cSPhilippe Mathieu-Daudé #else
632dc96009aSThomas Huth #define cpu_to_gt32(x) bswap32(x)
6330e45355cSPhilippe Mathieu-Daudé #endif
6340e45355cSPhilippe Mathieu-Daudé 
6350e45355cSPhilippe Mathieu-Daudé     /* setup MEM-to-PCI0 mapping as done by YAMON */
6360e45355cSPhilippe Mathieu-Daudé 
6370e45355cSPhilippe Mathieu-Daudé     /* move GT64120 registers from 0x14000000 to 0x1be00000 */
6380e45355cSPhilippe Mathieu-Daudé     bl_gen_write_u32(p, /* GT_ISD */
6390e45355cSPhilippe Mathieu-Daudé                      cpu_mips_phys_to_kseg1(NULL, 0x14000000 + 0x68),
6400e45355cSPhilippe Mathieu-Daudé                      cpu_to_gt32(0x1be00000 << 3));
6410e45355cSPhilippe Mathieu-Daudé 
6420e45355cSPhilippe Mathieu-Daudé     /* setup PCI0 io window to 0x18000000-0x181fffff */
6430e45355cSPhilippe Mathieu-Daudé     bl_gen_write_u32(p, /* GT_PCI0IOLD */
6440e45355cSPhilippe Mathieu-Daudé                      cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x48),
6450e45355cSPhilippe Mathieu-Daudé                      cpu_to_gt32(0x18000000 << 3));
6460e45355cSPhilippe Mathieu-Daudé     bl_gen_write_u32(p, /* GT_PCI0IOHD */
6470e45355cSPhilippe Mathieu-Daudé                      cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x50),
6480e45355cSPhilippe Mathieu-Daudé                      cpu_to_gt32(0x08000000 << 3));
6490e45355cSPhilippe Mathieu-Daudé 
6500e45355cSPhilippe Mathieu-Daudé     /* setup PCI0 mem windows */
6510e45355cSPhilippe Mathieu-Daudé     bl_gen_write_u32(p, /* GT_PCI0M0LD */
6520e45355cSPhilippe Mathieu-Daudé                      cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x58),
6530e45355cSPhilippe Mathieu-Daudé                      cpu_to_gt32(0x10000000 << 3));
6540e45355cSPhilippe Mathieu-Daudé     bl_gen_write_u32(p, /* GT_PCI0M0HD */
6550e45355cSPhilippe Mathieu-Daudé                      cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x60),
6560e45355cSPhilippe Mathieu-Daudé                      cpu_to_gt32(0x07e00000 << 3));
6570e45355cSPhilippe Mathieu-Daudé     bl_gen_write_u32(p, /* GT_PCI0M1LD */
6580e45355cSPhilippe Mathieu-Daudé                      cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x80),
6590e45355cSPhilippe Mathieu-Daudé                      cpu_to_gt32(0x18200000 << 3));
6600e45355cSPhilippe Mathieu-Daudé     bl_gen_write_u32(p, /* GT_PCI0M1HD */
6610e45355cSPhilippe Mathieu-Daudé                      cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0x88),
6620e45355cSPhilippe Mathieu-Daudé                      cpu_to_gt32(0x0bc00000 << 3));
6630e45355cSPhilippe Mathieu-Daudé 
6640e45355cSPhilippe Mathieu-Daudé #undef cpu_to_gt32
6650e45355cSPhilippe Mathieu-Daudé 
6661953dfa8SPhilippe Mathieu-Daudé     /*
6671953dfa8SPhilippe Mathieu-Daudé      * The PIIX ISA bridge is on PCI bus 0 dev 10 func 0.
6681953dfa8SPhilippe Mathieu-Daudé      * Load the PIIX IRQC[A:D] routing config address, then
6691953dfa8SPhilippe Mathieu-Daudé      * write routing configuration to the config data register.
6701953dfa8SPhilippe Mathieu-Daudé      */
6711953dfa8SPhilippe Mathieu-Daudé     bl_gen_write_u32(p, /* GT_PCI0_CFGADDR */
6721953dfa8SPhilippe Mathieu-Daudé                      cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0xcf8),
6731953dfa8SPhilippe Mathieu-Daudé                      tswap32((1 << 31) /* ConfigEn */
6741953dfa8SPhilippe Mathieu-Daudé                              | PCI_BUILD_BDF(0, PIIX4_PCI_DEVFN) << 8
6751953dfa8SPhilippe Mathieu-Daudé                              | PIIX_PIRQCA));
6761953dfa8SPhilippe Mathieu-Daudé     bl_gen_write_u32(p, /* GT_PCI0_CFGDATA */
6771953dfa8SPhilippe Mathieu-Daudé                      cpu_mips_phys_to_kseg1(NULL, 0x1be00000 + 0xcfc),
6781953dfa8SPhilippe Mathieu-Daudé                      tswap32(ldl_be_p(pci_pins_cfg)));
6791953dfa8SPhilippe Mathieu-Daudé 
6800e45355cSPhilippe Mathieu-Daudé     bl_gen_jump_kernel(p,
6810e45355cSPhilippe Mathieu-Daudé                        true, ENVP_VADDR - 64,
6820e45355cSPhilippe Mathieu-Daudé                        /*
6830e45355cSPhilippe Mathieu-Daudé                         * If semihosting is used, arguments have already
6840e45355cSPhilippe Mathieu-Daudé                         * been passed, so we preserve $a0.
6850e45355cSPhilippe Mathieu-Daudé                         */
6860e45355cSPhilippe Mathieu-Daudé                        !semihosting_get_argc(), 2,
6870e45355cSPhilippe Mathieu-Daudé                        true, ENVP_VADDR,
6880e45355cSPhilippe Mathieu-Daudé                        true, ENVP_VADDR + 8,
6890e45355cSPhilippe Mathieu-Daudé                        true, loaderparams.ram_low_size,
6900e45355cSPhilippe Mathieu-Daudé                        kernel_entry);
6910e45355cSPhilippe Mathieu-Daudé }
6920e45355cSPhilippe Mathieu-Daudé 
write_bootloader_nanomips(uint8_t * base,uint64_t run_addr,uint64_t kernel_entry)693dde98994SJiaxun Yang static void write_bootloader_nanomips(uint8_t *base, uint64_t run_addr,
694dde98994SJiaxun Yang                                       uint64_t kernel_entry)
6955298722eSAleksandar Markovic {
6965298722eSAleksandar Markovic     uint16_t *p;
6975298722eSAleksandar Markovic 
6985298722eSAleksandar Markovic     /* Small bootloader */
6995298722eSAleksandar Markovic     p = (uint16_t *)base;
7005298722eSAleksandar Markovic 
7015298722eSAleksandar Markovic     stw_p(p++, 0x2800); stw_p(p++, 0x001c);
7025298722eSAleksandar Markovic                                 /* bc to_here */
7035298722eSAleksandar Markovic     stw_p(p++, 0x8000); stw_p(p++, 0xc000);
7045298722eSAleksandar Markovic                                 /* nop */
7055298722eSAleksandar Markovic     stw_p(p++, 0x8000); stw_p(p++, 0xc000);
7065298722eSAleksandar Markovic                                 /* nop */
7075298722eSAleksandar Markovic     stw_p(p++, 0x8000); stw_p(p++, 0xc000);
7085298722eSAleksandar Markovic                                 /* nop */
7095298722eSAleksandar Markovic     stw_p(p++, 0x8000); stw_p(p++, 0xc000);
7105298722eSAleksandar Markovic                                 /* nop */
7115298722eSAleksandar Markovic     stw_p(p++, 0x8000); stw_p(p++, 0xc000);
7125298722eSAleksandar Markovic                                 /* nop */
7135298722eSAleksandar Markovic     stw_p(p++, 0x8000); stw_p(p++, 0xc000);
7145298722eSAleksandar Markovic                                 /* nop */
7155298722eSAleksandar Markovic     stw_p(p++, 0x8000); stw_p(p++, 0xc000);
7165298722eSAleksandar Markovic                                 /* nop */
7175298722eSAleksandar Markovic 
7185298722eSAleksandar Markovic     /* to_here: */
7195298722eSAleksandar Markovic 
7200e45355cSPhilippe Mathieu-Daudé     bl_setup_gt64120_jump_kernel((void **)&p, run_addr, kernel_entry);
7215298722eSAleksandar Markovic }
7225298722eSAleksandar Markovic 
7235298722eSAleksandar Markovic /*
7245298722eSAleksandar Markovic  * ROM and pseudo bootloader
7255298722eSAleksandar Markovic  *
7265298722eSAleksandar Markovic  * The following code implements a very very simple bootloader. It first
7275298722eSAleksandar Markovic  * loads the registers a0 to a3 to the values expected by the OS, and
7285298722eSAleksandar Markovic  * then jump at the kernel address.
7295298722eSAleksandar Markovic  *
7305298722eSAleksandar Markovic  * The bootloader should pass the locations of the kernel arguments and
7315298722eSAleksandar Markovic  * environment variables tables. Those tables contain the 32-bit address
7325298722eSAleksandar Markovic  * of NULL terminated strings. The environment variables table should be
7335298722eSAleksandar Markovic  * terminated by a NULL address.
7345298722eSAleksandar Markovic  *
7355298722eSAleksandar Markovic  * For a simpler implementation, the number of kernel arguments is fixed
7365298722eSAleksandar Markovic  * to two (the name of the kernel and the command line), and the two
7375298722eSAleksandar Markovic  * tables are actually the same one.
7385298722eSAleksandar Markovic  *
7395298722eSAleksandar Markovic  * The registers a0 to a3 should contain the following values:
7405298722eSAleksandar Markovic  *   a0 - number of kernel arguments
7415298722eSAleksandar Markovic  *   a1 - 32-bit address of the kernel arguments table
7425298722eSAleksandar Markovic  *   a2 - 32-bit address of the environment variables table
7435298722eSAleksandar Markovic  *   a3 - RAM size in bytes
7445298722eSAleksandar Markovic  */
write_bootloader(uint8_t * base,uint64_t run_addr,uint64_t kernel_entry)745dde98994SJiaxun Yang static void write_bootloader(uint8_t *base, uint64_t run_addr,
746dde98994SJiaxun Yang                              uint64_t kernel_entry)
7475298722eSAleksandar Markovic {
7485298722eSAleksandar Markovic     uint32_t *p;
7495298722eSAleksandar Markovic 
7505298722eSAleksandar Markovic     /* Small bootloader */
7515298722eSAleksandar Markovic     p = (uint32_t *)base;
7525298722eSAleksandar Markovic 
7535298722eSAleksandar Markovic     stl_p(p++, 0x08000000 |                  /* j 0x1fc00580 */
7545298722eSAleksandar Markovic                  ((run_addr + 0x580) & 0x0fffffff) >> 2);
7555298722eSAleksandar Markovic     stl_p(p++, 0x00000000);                  /* nop */
7565298722eSAleksandar Markovic 
7575298722eSAleksandar Markovic     /* YAMON service vector */
7585298722eSAleksandar Markovic     stl_p(base + 0x500, run_addr + 0x0580);  /* start: */
7595298722eSAleksandar Markovic     stl_p(base + 0x504, run_addr + 0x083c);  /* print_count: */
7605298722eSAleksandar Markovic     stl_p(base + 0x520, run_addr + 0x0580);  /* start: */
7615298722eSAleksandar Markovic     stl_p(base + 0x52c, run_addr + 0x0800);  /* flush_cache: */
7625298722eSAleksandar Markovic     stl_p(base + 0x534, run_addr + 0x0808);  /* print: */
7635298722eSAleksandar Markovic     stl_p(base + 0x538, run_addr + 0x0800);  /* reg_cpu_isr: */
7645298722eSAleksandar Markovic     stl_p(base + 0x53c, run_addr + 0x0800);  /* unred_cpu_isr: */
7655298722eSAleksandar Markovic     stl_p(base + 0x540, run_addr + 0x0800);  /* reg_ic_isr: */
7665298722eSAleksandar Markovic     stl_p(base + 0x544, run_addr + 0x0800);  /* unred_ic_isr: */
7675298722eSAleksandar Markovic     stl_p(base + 0x548, run_addr + 0x0800);  /* reg_esr: */
7685298722eSAleksandar Markovic     stl_p(base + 0x54c, run_addr + 0x0800);  /* unreg_esr: */
7695298722eSAleksandar Markovic     stl_p(base + 0x550, run_addr + 0x0800);  /* getchar: */
7705298722eSAleksandar Markovic     stl_p(base + 0x554, run_addr + 0x0800);  /* syscon_read: */
7715298722eSAleksandar Markovic 
7725298722eSAleksandar Markovic 
7735298722eSAleksandar Markovic     /* Second part of the bootloader */
7745298722eSAleksandar Markovic     p = (uint32_t *) (base + 0x580);
7755298722eSAleksandar Markovic 
7760c8427baSJiaxun Yang     /*
7770c8427baSJiaxun Yang      * Load BAR registers as done by YAMON:
7780c8427baSJiaxun Yang      *
7790c8427baSJiaxun Yang      *  - set up PCI0 I/O BARs from 0x18000000 to 0x181fffff
7800c8427baSJiaxun Yang      *  - set up PCI0 MEM0 at 0x10000000, size 0x7e00000
7810c8427baSJiaxun Yang      *  - set up PCI0 MEM1 at 0x18200000, size 0xbc00000
7820c8427baSJiaxun Yang      *
7830c8427baSJiaxun Yang      */
7845298722eSAleksandar Markovic 
7859d8299bfSPeter Maydell     bl_setup_gt64120_jump_kernel((void **)&p, run_addr, kernel_entry);
7865298722eSAleksandar Markovic 
7875298722eSAleksandar Markovic     /* YAMON subroutines */
7885298722eSAleksandar Markovic     p = (uint32_t *) (base + 0x800);
7895298722eSAleksandar Markovic     stl_p(p++, 0x03e00009);                  /* jalr ra */
7905298722eSAleksandar Markovic     stl_p(p++, 0x24020000);                  /* li v0,0 */
7915298722eSAleksandar Markovic     /* 808 YAMON print */
7925298722eSAleksandar Markovic     stl_p(p++, 0x03e06821);                  /* move t5,ra */
7935298722eSAleksandar Markovic     stl_p(p++, 0x00805821);                  /* move t3,a0 */
7945298722eSAleksandar Markovic     stl_p(p++, 0x00a05021);                  /* move t2,a1 */
7955298722eSAleksandar Markovic     stl_p(p++, 0x91440000);                  /* lbu a0,0(t2) */
7965298722eSAleksandar Markovic     stl_p(p++, 0x254a0001);                  /* addiu t2,t2,1 */
7975298722eSAleksandar Markovic     stl_p(p++, 0x10800005);                  /* beqz a0,834 */
7985298722eSAleksandar Markovic     stl_p(p++, 0x00000000);                  /* nop */
7995298722eSAleksandar Markovic     stl_p(p++, 0x0ff0021c);                  /* jal 870 */
8005298722eSAleksandar Markovic     stl_p(p++, 0x00000000);                  /* nop */
8015298722eSAleksandar Markovic     stl_p(p++, 0x1000fff9);                  /* b 814 */
8025298722eSAleksandar Markovic     stl_p(p++, 0x00000000);                  /* nop */
8035298722eSAleksandar Markovic     stl_p(p++, 0x01a00009);                  /* jalr t5 */
8045298722eSAleksandar Markovic     stl_p(p++, 0x01602021);                  /* move a0,t3 */
8055298722eSAleksandar Markovic     /* 0x83c YAMON print_count */
8065298722eSAleksandar Markovic     stl_p(p++, 0x03e06821);                  /* move t5,ra */
8075298722eSAleksandar Markovic     stl_p(p++, 0x00805821);                  /* move t3,a0 */
8085298722eSAleksandar Markovic     stl_p(p++, 0x00a05021);                  /* move t2,a1 */
8095298722eSAleksandar Markovic     stl_p(p++, 0x00c06021);                  /* move t4,a2 */
8105298722eSAleksandar Markovic     stl_p(p++, 0x91440000);                  /* lbu a0,0(t2) */
8115298722eSAleksandar Markovic     stl_p(p++, 0x0ff0021c);                  /* jal 870 */
8125298722eSAleksandar Markovic     stl_p(p++, 0x00000000);                  /* nop */
8135298722eSAleksandar Markovic     stl_p(p++, 0x254a0001);                  /* addiu t2,t2,1 */
8145298722eSAleksandar Markovic     stl_p(p++, 0x258cffff);                  /* addiu t4,t4,-1 */
8155298722eSAleksandar Markovic     stl_p(p++, 0x1580fffa);                  /* bnez t4,84c */
8165298722eSAleksandar Markovic     stl_p(p++, 0x00000000);                  /* nop */
8175298722eSAleksandar Markovic     stl_p(p++, 0x01a00009);                  /* jalr t5 */
8185298722eSAleksandar Markovic     stl_p(p++, 0x01602021);                  /* move a0,t3 */
8195298722eSAleksandar Markovic     /* 0x870 */
8205298722eSAleksandar Markovic     stl_p(p++, 0x3c08b800);                  /* lui t0,0xb400 */
8215298722eSAleksandar Markovic     stl_p(p++, 0x350803f8);                  /* ori t0,t0,0x3f8 */
8225298722eSAleksandar Markovic     stl_p(p++, 0x91090005);                  /* lbu t1,5(t0) */
8235298722eSAleksandar Markovic     stl_p(p++, 0x00000000);                  /* nop */
8245298722eSAleksandar Markovic     stl_p(p++, 0x31290040);                  /* andi t1,t1,0x40 */
8255298722eSAleksandar Markovic     stl_p(p++, 0x1120fffc);                  /* beqz t1,878 <outch+0x8> */
8265298722eSAleksandar Markovic     stl_p(p++, 0x00000000);                  /* nop */
8275298722eSAleksandar Markovic     stl_p(p++, 0x03e00009);                  /* jalr ra */
8285298722eSAleksandar Markovic     stl_p(p++, 0xa1040000);                  /* sb a0,0(t0) */
8295298722eSAleksandar Markovic }
8305298722eSAleksandar Markovic 
prom_set(uint32_t * prom_buf,int index,const char * string,...)8319edc6313SMarc-André Lureau static void G_GNUC_PRINTF(3, 4) prom_set(uint32_t *prom_buf, int index,
8325298722eSAleksandar Markovic                                         const char *string, ...)
8335298722eSAleksandar Markovic {
8345298722eSAleksandar Markovic     va_list ap;
835dde98994SJiaxun Yang     uint32_t table_addr;
8365298722eSAleksandar Markovic 
8375298722eSAleksandar Markovic     if (index >= ENVP_NB_ENTRIES) {
8385298722eSAleksandar Markovic         return;
8395298722eSAleksandar Markovic     }
8405298722eSAleksandar Markovic 
8415298722eSAleksandar Markovic     if (string == NULL) {
8425298722eSAleksandar Markovic         prom_buf[index] = 0;
8435298722eSAleksandar Markovic         return;
8445298722eSAleksandar Markovic     }
8455298722eSAleksandar Markovic 
846dde98994SJiaxun Yang     table_addr = sizeof(uint32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
847df055c65SJiaxun Yang     prom_buf[index] = tswap32(ENVP_VADDR + table_addr);
8485298722eSAleksandar Markovic 
8495298722eSAleksandar Markovic     va_start(ap, string);
8505298722eSAleksandar Markovic     vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
8515298722eSAleksandar Markovic     va_end(ap);
8525298722eSAleksandar Markovic }
8535298722eSAleksandar Markovic 
rng_seed_hex_new(void)8543a8ff366SPhilippe Mathieu-Daudé static GString *rng_seed_hex_new(void)
8556233a138SJason A. Donenfeld {
8566233a138SJason A. Donenfeld     uint8_t rng_seed[32];
8576233a138SJason A. Donenfeld 
8586233a138SJason A. Donenfeld     qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
8593a8ff366SPhilippe Mathieu-Daudé     return qemu_hexdump_line(NULL, rng_seed, sizeof(rng_seed), 0, 0);
8606233a138SJason A. Donenfeld }
8613a8ff366SPhilippe Mathieu-Daudé 
reinitialize_rng_seed(void * opaque)8623a8ff366SPhilippe Mathieu-Daudé static void reinitialize_rng_seed(void *opaque)
8633a8ff366SPhilippe Mathieu-Daudé {
8643a8ff366SPhilippe Mathieu-Daudé     g_autoptr(GString) hex = rng_seed_hex_new();
8653a8ff366SPhilippe Mathieu-Daudé     memcpy(opaque, hex->str, hex->len);
8666233a138SJason A. Donenfeld }
8676233a138SJason A. Donenfeld 
8685298722eSAleksandar Markovic /* Kernel */
load_kernel(void)869dde98994SJiaxun Yang static uint64_t load_kernel(void)
8705298722eSAleksandar Markovic {
871dde98994SJiaxun Yang     uint64_t kernel_entry, kernel_high, initrd_size;
8725298722eSAleksandar Markovic     long kernel_size;
8735298722eSAleksandar Markovic     ram_addr_t initrd_offset;
8745298722eSAleksandar Markovic     uint32_t *prom_buf;
8755298722eSAleksandar Markovic     long prom_size;
8765298722eSAleksandar Markovic     int prom_index = 0;
8776233a138SJason A. Donenfeld     size_t rng_seed_prom_offset;
8785298722eSAleksandar Markovic 
8795298722eSAleksandar Markovic     kernel_size = load_elf(loaderparams.kernel_filename, NULL,
8805298722eSAleksandar Markovic                            cpu_mips_kseg0_to_phys, NULL,
881dde98994SJiaxun Yang                            &kernel_entry, NULL,
882ded625e7SThomas Huth                            &kernel_high, NULL, TARGET_BIG_ENDIAN, EM_MIPS,
8835298722eSAleksandar Markovic                            1, 0);
8845298722eSAleksandar Markovic     if (kernel_size < 0) {
8855298722eSAleksandar Markovic         error_report("could not load kernel '%s': %s",
8865298722eSAleksandar Markovic                      loaderparams.kernel_filename,
8875298722eSAleksandar Markovic                      load_elf_strerror(kernel_size));
8885298722eSAleksandar Markovic         exit(1);
8895298722eSAleksandar Markovic     }
8905298722eSAleksandar Markovic 
8915298722eSAleksandar Markovic     /* Check where the kernel has been linked */
892a8448735SPaolo Bonzini     if (kernel_entry <= USEG_LIMIT) {
893a8448735SPaolo Bonzini         error_report("Trap-and-Emul kernels (Linux CONFIG_KVM_GUEST)"
894a8448735SPaolo Bonzini                      " are not supported");
8955298722eSAleksandar Markovic         exit(1);
8965298722eSAleksandar Markovic     }
8975298722eSAleksandar Markovic 
8985298722eSAleksandar Markovic     /* load initrd */
8995298722eSAleksandar Markovic     initrd_size = 0;
9005298722eSAleksandar Markovic     initrd_offset = 0;
9015298722eSAleksandar Markovic     if (loaderparams.initrd_filename) {
9025298722eSAleksandar Markovic         initrd_size = get_image_size(loaderparams.initrd_filename);
9035298722eSAleksandar Markovic         if (initrd_size > 0) {
9045298722eSAleksandar Markovic             /*
9055298722eSAleksandar Markovic              * The kernel allocates the bootmap memory in the low memory after
9065298722eSAleksandar Markovic              * the initrd.  It takes at most 128kiB for 2GB RAM and 4kiB
9075298722eSAleksandar Markovic              * pages.
9085298722eSAleksandar Markovic              */
909acab36caSPhilippe Mathieu-Daudé             initrd_offset = ROUND_UP(loaderparams.ram_low_size
910acab36caSPhilippe Mathieu-Daudé                                      - (initrd_size + 128 * KiB),
911acab36caSPhilippe Mathieu-Daudé                                      INITRD_PAGE_SIZE);
9125298722eSAleksandar Markovic             if (kernel_high >= initrd_offset) {
9135298722eSAleksandar Markovic                 error_report("memory too small for initial ram disk '%s'",
9145298722eSAleksandar Markovic                              loaderparams.initrd_filename);
9155298722eSAleksandar Markovic                 exit(1);
9165298722eSAleksandar Markovic             }
9175298722eSAleksandar Markovic             initrd_size = load_image_targphys(loaderparams.initrd_filename,
9185298722eSAleksandar Markovic                                               initrd_offset,
91974d6bf85SPaolo Bonzini                                               loaderparams.ram_size - initrd_offset);
9205298722eSAleksandar Markovic         }
9215298722eSAleksandar Markovic         if (initrd_size == (target_ulong) -1) {
9225298722eSAleksandar Markovic             error_report("could not load initial ram disk '%s'",
9235298722eSAleksandar Markovic                          loaderparams.initrd_filename);
9245298722eSAleksandar Markovic             exit(1);
9255298722eSAleksandar Markovic         }
9265298722eSAleksandar Markovic     }
9275298722eSAleksandar Markovic 
9285298722eSAleksandar Markovic     /* Setup prom parameters. */
9295298722eSAleksandar Markovic     prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
9305298722eSAleksandar Markovic     prom_buf = g_malloc(prom_size);
9315298722eSAleksandar Markovic 
9325298722eSAleksandar Markovic     prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
9335298722eSAleksandar Markovic     if (initrd_size > 0) {
9345298722eSAleksandar Markovic         prom_set(prom_buf, prom_index++,
9355298722eSAleksandar Markovic                  "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s",
936a8448735SPaolo Bonzini                  cpu_mips_phys_to_kseg0(NULL, initrd_offset),
9375298722eSAleksandar Markovic                  initrd_size, loaderparams.kernel_cmdline);
9385298722eSAleksandar Markovic     } else {
9395298722eSAleksandar Markovic         prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
9405298722eSAleksandar Markovic     }
9415298722eSAleksandar Markovic 
9425298722eSAleksandar Markovic     prom_set(prom_buf, prom_index++, "memsize");
9435298722eSAleksandar Markovic     prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_low_size);
9445298722eSAleksandar Markovic 
9455298722eSAleksandar Markovic     prom_set(prom_buf, prom_index++, "ememsize");
9465298722eSAleksandar Markovic     prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_size);
9475298722eSAleksandar Markovic 
9485298722eSAleksandar Markovic     prom_set(prom_buf, prom_index++, "modetty0");
9495298722eSAleksandar Markovic     prom_set(prom_buf, prom_index++, "38400n8r");
9506233a138SJason A. Donenfeld 
9516233a138SJason A. Donenfeld     prom_set(prom_buf, prom_index++, "rngseed");
9526233a138SJason A. Donenfeld     rng_seed_prom_offset = prom_index * ENVP_ENTRY_SIZE +
9536233a138SJason A. Donenfeld                            sizeof(uint32_t) * ENVP_NB_ENTRIES;
9543a8ff366SPhilippe Mathieu-Daudé     {
9553a8ff366SPhilippe Mathieu-Daudé         g_autoptr(GString) hex = rng_seed_hex_new();
9563a8ff366SPhilippe Mathieu-Daudé         prom_set(prom_buf, prom_index++, "%s", hex->str);
9573a8ff366SPhilippe Mathieu-Daudé     }
9586233a138SJason A. Donenfeld 
9595298722eSAleksandar Markovic     prom_set(prom_buf, prom_index++, NULL);
9605298722eSAleksandar Markovic 
961df055c65SJiaxun Yang     rom_add_blob_fixed("prom", prom_buf, prom_size, ENVP_PADDR);
9626233a138SJason A. Donenfeld     qemu_register_reset_nosnapshotload(reinitialize_rng_seed,
9636233a138SJason A. Donenfeld             rom_ptr(ENVP_PADDR, prom_size) + rng_seed_prom_offset);
9645298722eSAleksandar Markovic 
9655298722eSAleksandar Markovic     g_free(prom_buf);
9665298722eSAleksandar Markovic     return kernel_entry;
9675298722eSAleksandar Markovic }
9685298722eSAleksandar Markovic 
malta_mips_config(MIPSCPU * cpu)9695298722eSAleksandar Markovic static void malta_mips_config(MIPSCPU *cpu)
9705298722eSAleksandar Markovic {
9715298722eSAleksandar Markovic     MachineState *ms = MACHINE(qdev_get_machine());
9725298722eSAleksandar Markovic     unsigned int smp_cpus = ms->smp.cpus;
9735298722eSAleksandar Markovic     CPUMIPSState *env = &cpu->env;
9745298722eSAleksandar Markovic     CPUState *cs = CPU(cpu);
9755298722eSAleksandar Markovic 
9768de0f280SPhilippe Mathieu-Daudé     if (ase_mt_available(env)) {
97707741e67SPhilippe Mathieu-Daudé         env->mvp->CP0_MVPConf0 = deposit32(env->mvp->CP0_MVPConf0,
97807741e67SPhilippe Mathieu-Daudé                                            CP0MVPC0_PTC, 8,
97907741e67SPhilippe Mathieu-Daudé                                            smp_cpus * cs->nr_threads - 1);
98007741e67SPhilippe Mathieu-Daudé         env->mvp->CP0_MVPConf0 = deposit32(env->mvp->CP0_MVPConf0,
98107741e67SPhilippe Mathieu-Daudé                                            CP0MVPC0_PVPE, 4, smp_cpus - 1);
9825298722eSAleksandar Markovic     }
9838de0f280SPhilippe Mathieu-Daudé }
9845298722eSAleksandar Markovic 
malta_pci_slot_get_pirq(PCIDevice * pci_dev,int irq_num)9853c73d590SBernhard Beschow static int malta_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
9863c73d590SBernhard Beschow {
9873c73d590SBernhard Beschow     int slot;
9883c73d590SBernhard Beschow 
9893c73d590SBernhard Beschow     slot = PCI_SLOT(pci_dev->devfn);
9903c73d590SBernhard Beschow 
9913c73d590SBernhard Beschow     switch (slot) {
9923c73d590SBernhard Beschow     /* PIIX4 USB */
9933c73d590SBernhard Beschow     case 10:
9943c73d590SBernhard Beschow         return 3;
9953c73d590SBernhard Beschow     /* AMD 79C973 Ethernet */
9963c73d590SBernhard Beschow     case 11:
9973c73d590SBernhard Beschow         return 1;
9983c73d590SBernhard Beschow     /* Crystal 4281 Sound */
9993c73d590SBernhard Beschow     case 12:
10003c73d590SBernhard Beschow         return 2;
10013c73d590SBernhard Beschow     /* PCI slot 1 to 4 */
10023c73d590SBernhard Beschow     case 18 ... 21:
10033c73d590SBernhard Beschow         return ((slot - 18) + irq_num) & 0x03;
10043c73d590SBernhard Beschow     /* Unknown device, don't do any translation */
10053c73d590SBernhard Beschow     default:
10063c73d590SBernhard Beschow         return irq_num;
10073c73d590SBernhard Beschow     }
10083c73d590SBernhard Beschow }
10093c73d590SBernhard Beschow 
main_cpu_reset(void * opaque)10105298722eSAleksandar Markovic static void main_cpu_reset(void *opaque)
10115298722eSAleksandar Markovic {
10125298722eSAleksandar Markovic     MIPSCPU *cpu = opaque;
10135298722eSAleksandar Markovic     CPUMIPSState *env = &cpu->env;
10145298722eSAleksandar Markovic 
10155298722eSAleksandar Markovic     cpu_reset(CPU(cpu));
10165298722eSAleksandar Markovic 
10175298722eSAleksandar Markovic     /*
10185298722eSAleksandar Markovic      * The bootloader does not need to be rewritten as it is located in a
10195298722eSAleksandar Markovic      * read only location. The kernel location and the arguments table
10205298722eSAleksandar Markovic      * location does not change.
10215298722eSAleksandar Markovic      */
10225298722eSAleksandar Markovic     if (loaderparams.kernel_filename) {
10235298722eSAleksandar Markovic         env->CP0_Status &= ~(1 << CP0St_ERL);
10245298722eSAleksandar Markovic     }
10255298722eSAleksandar Markovic 
10265298722eSAleksandar Markovic     malta_mips_config(cpu);
10275298722eSAleksandar Markovic }
10285298722eSAleksandar Markovic 
create_cpu_without_cps(MachineState * ms,MaltaState * s,qemu_irq * cbus_irq,qemu_irq * i8259_irq)1029eea1f5baSPhilippe Mathieu-Daudé static void create_cpu_without_cps(MachineState *ms, MaltaState *s,
10305298722eSAleksandar Markovic                                    qemu_irq *cbus_irq, qemu_irq *i8259_irq)
10315298722eSAleksandar Markovic {
10325298722eSAleksandar Markovic     CPUMIPSState *env;
10335298722eSAleksandar Markovic     MIPSCPU *cpu;
10345298722eSAleksandar Markovic     int i;
10355298722eSAleksandar Markovic 
10365298722eSAleksandar Markovic     for (i = 0; i < ms->smp.cpus; i++) {
1037*3e8f019bSPhilippe Mathieu-Daudé         cpu = mips_cpu_create_with_clock(ms->cpu_type, s->cpuclk,
1038*3e8f019bSPhilippe Mathieu-Daudé                                          TARGET_BIG_ENDIAN);
10395298722eSAleksandar Markovic 
10405298722eSAleksandar Markovic         /* Init internal devices */
10415298722eSAleksandar Markovic         cpu_mips_irq_init_cpu(cpu);
10425298722eSAleksandar Markovic         cpu_mips_clock_init(cpu);
10435298722eSAleksandar Markovic         qemu_register_reset(main_cpu_reset, cpu);
10445298722eSAleksandar Markovic     }
10455298722eSAleksandar Markovic 
10465298722eSAleksandar Markovic     cpu = MIPS_CPU(first_cpu);
10475298722eSAleksandar Markovic     env = &cpu->env;
10485298722eSAleksandar Markovic     *i8259_irq = env->irq[2];
10495298722eSAleksandar Markovic     *cbus_irq = env->irq[4];
10505298722eSAleksandar Markovic }
10515298722eSAleksandar Markovic 
create_cps(MachineState * ms,MaltaState * s,qemu_irq * cbus_irq,qemu_irq * i8259_irq)10525298722eSAleksandar Markovic static void create_cps(MachineState *ms, MaltaState *s,
10535298722eSAleksandar Markovic                        qemu_irq *cbus_irq, qemu_irq *i8259_irq)
10545298722eSAleksandar Markovic {
10550074fce6SMarkus Armbruster     object_initialize_child(OBJECT(s), "cps", &s->cps, TYPE_MIPS_CPS);
10565325cc34SMarkus Armbruster     object_property_set_str(OBJECT(&s->cps), "cpu-type", ms->cpu_type,
1057aacc7c8bSPeter Maydell                             &error_fatal);
1058805659a8SPhilippe Mathieu-Daudé     object_property_set_bool(OBJECT(&s->cps), "cpu-big-endian",
1059805659a8SPhilippe Mathieu-Daudé                              TARGET_BIG_ENDIAN, &error_abort);
106010997f2dSPhilippe Mathieu-Daudé     object_property_set_uint(OBJECT(&s->cps), "num-vp", ms->smp.cpus,
1061aacc7c8bSPeter Maydell                             &error_fatal);
1062eea1f5baSPhilippe Mathieu-Daudé     qdev_connect_clock_in(DEVICE(&s->cps), "clk-in", s->cpuclk);
10630074fce6SMarkus Armbruster     sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal);
10645298722eSAleksandar Markovic 
10655298722eSAleksandar Markovic     sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1);
10665298722eSAleksandar Markovic 
10675298722eSAleksandar Markovic     *i8259_irq = get_cps_irq(&s->cps, 3);
10685298722eSAleksandar Markovic     *cbus_irq = NULL;
10695298722eSAleksandar Markovic }
10705298722eSAleksandar Markovic 
mips_create_cpu(MachineState * ms,MaltaState * s,qemu_irq * cbus_irq,qemu_irq * i8259_irq)10715298722eSAleksandar Markovic static void mips_create_cpu(MachineState *ms, MaltaState *s,
10725298722eSAleksandar Markovic                             qemu_irq *cbus_irq, qemu_irq *i8259_irq)
10735298722eSAleksandar Markovic {
1074ac70f976SPhilippe Mathieu-Daudé     if ((ms->smp.cpus > 1) && cpu_type_supports_cps_smp(ms->cpu_type)) {
10755298722eSAleksandar Markovic         create_cps(ms, s, cbus_irq, i8259_irq);
10765298722eSAleksandar Markovic     } else {
1077eea1f5baSPhilippe Mathieu-Daudé         create_cpu_without_cps(ms, s, cbus_irq, i8259_irq);
10785298722eSAleksandar Markovic     }
10795298722eSAleksandar Markovic }
10805298722eSAleksandar Markovic 
10815298722eSAleksandar Markovic static
mips_malta_init(MachineState * machine)10825298722eSAleksandar Markovic void mips_malta_init(MachineState *machine)
10835298722eSAleksandar Markovic {
10845298722eSAleksandar Markovic     ram_addr_t ram_size = machine->ram_size;
10855298722eSAleksandar Markovic     ram_addr_t ram_low_size;
10865298722eSAleksandar Markovic     const char *kernel_filename = machine->kernel_filename;
10875298722eSAleksandar Markovic     const char *kernel_cmdline = machine->kernel_cmdline;
10885298722eSAleksandar Markovic     const char *initrd_filename = machine->initrd_filename;
10895298722eSAleksandar Markovic     char *filename;
10905298722eSAleksandar Markovic     PFlashCFI01 *fl;
10915298722eSAleksandar Markovic     MemoryRegion *system_memory = get_system_memory();
10925298722eSAleksandar Markovic     MemoryRegion *ram_low_preio = g_new(MemoryRegion, 1);
10935298722eSAleksandar Markovic     MemoryRegion *ram_low_postio;
10945298722eSAleksandar Markovic     MemoryRegion *bios, *bios_copy = g_new(MemoryRegion, 1);
10955298722eSAleksandar Markovic     const size_t smbus_eeprom_size = 8 * 256;
10965298722eSAleksandar Markovic     uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
1097dde98994SJiaxun Yang     uint64_t kernel_entry, bootloader_run_addr;
10985298722eSAleksandar Markovic     PCIBus *pci_bus;
10995298722eSAleksandar Markovic     ISABus *isa_bus;
11005298722eSAleksandar Markovic     qemu_irq cbus_irq, i8259_irq;
11015298722eSAleksandar Markovic     I2CBus *smbus;
11025298722eSAleksandar Markovic     DriveInfo *dinfo;
11035298722eSAleksandar Markovic     int fl_idx = 0;
11048df525a5SPhilippe Mathieu-Daudé     MaltaState *s;
1105e8ebf549SBernhard Beschow     PCIDevice *piix4;
11068df525a5SPhilippe Mathieu-Daudé     DeviceState *dev;
11075298722eSAleksandar Markovic 
11088df525a5SPhilippe Mathieu-Daudé     s = MIPS_MALTA(qdev_new(TYPE_MIPS_MALTA));
11098df525a5SPhilippe Mathieu-Daudé     sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal);
11105298722eSAleksandar Markovic 
11115298722eSAleksandar Markovic     /* create CPU */
11125298722eSAleksandar Markovic     mips_create_cpu(machine, s, &cbus_irq, &i8259_irq);
11135298722eSAleksandar Markovic 
11145298722eSAleksandar Markovic     /* allocate RAM */
11155298722eSAleksandar Markovic     if (ram_size > 2 * GiB) {
11165298722eSAleksandar Markovic         error_report("Too much memory for this machine: %" PRId64 "MB,"
11175298722eSAleksandar Markovic                      " maximum 2048MB", ram_size / MiB);
11185298722eSAleksandar Markovic         exit(1);
11195298722eSAleksandar Markovic     }
11205298722eSAleksandar Markovic 
11215298722eSAleksandar Markovic     /* register RAM at high address where it is undisturbed by IO */
11225298722eSAleksandar Markovic     memory_region_add_subregion(system_memory, 0x80000000, machine->ram);
11235298722eSAleksandar Markovic 
11245298722eSAleksandar Markovic     /* alias for pre IO hole access */
11255298722eSAleksandar Markovic     memory_region_init_alias(ram_low_preio, NULL, "mips_malta_low_preio.ram",
11265298722eSAleksandar Markovic                              machine->ram, 0, MIN(ram_size, 256 * MiB));
11275298722eSAleksandar Markovic     memory_region_add_subregion(system_memory, 0, ram_low_preio);
11285298722eSAleksandar Markovic 
11295298722eSAleksandar Markovic     /* alias for post IO hole access, if there is enough RAM */
11305298722eSAleksandar Markovic     if (ram_size > 512 * MiB) {
11315298722eSAleksandar Markovic         ram_low_postio = g_new(MemoryRegion, 1);
11325298722eSAleksandar Markovic         memory_region_init_alias(ram_low_postio, NULL,
11335298722eSAleksandar Markovic                                  "mips_malta_low_postio.ram",
11345298722eSAleksandar Markovic                                  machine->ram, 512 * MiB,
11355298722eSAleksandar Markovic                                  ram_size - 512 * MiB);
11365298722eSAleksandar Markovic         memory_region_add_subregion(system_memory, 512 * MiB,
11375298722eSAleksandar Markovic                                     ram_low_postio);
11385298722eSAleksandar Markovic     }
11395298722eSAleksandar Markovic 
11405298722eSAleksandar Markovic     /* FPGA */
11415298722eSAleksandar Markovic 
11425298722eSAleksandar Markovic     /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
11435298722eSAleksandar Markovic     malta_fpga_init(system_memory, FPGA_ADDRESS, cbus_irq, serial_hd(2));
11445298722eSAleksandar Markovic 
11455298722eSAleksandar Markovic     /* Load firmware in flash / BIOS. */
11465298722eSAleksandar Markovic     dinfo = drive_get(IF_PFLASH, 0, fl_idx);
11475298722eSAleksandar Markovic     fl = pflash_cfi01_register(FLASH_ADDRESS, "mips_malta.bios",
11485298722eSAleksandar Markovic                                FLASH_SIZE,
11495298722eSAleksandar Markovic                                dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
11505298722eSAleksandar Markovic                                65536,
1151ded625e7SThomas Huth                                4, 0x0000, 0x0000, 0x0000, 0x0000,
1152ded625e7SThomas Huth                                TARGET_BIG_ENDIAN);
11535298722eSAleksandar Markovic     bios = pflash_cfi01_get_memory(fl);
11545298722eSAleksandar Markovic     fl_idx++;
11555298722eSAleksandar Markovic     if (kernel_filename) {
11565298722eSAleksandar Markovic         ram_low_size = MIN(ram_size, 256 * MiB);
11575052b6e8SJiaxun Yang         bootloader_run_addr = cpu_mips_phys_to_kseg0(NULL, RESET_ADDRESS);
11585298722eSAleksandar Markovic 
11595298722eSAleksandar Markovic         /* Write a small bootloader to the flash location. */
11605298722eSAleksandar Markovic         loaderparams.ram_size = ram_size;
11615298722eSAleksandar Markovic         loaderparams.ram_low_size = ram_low_size;
11625298722eSAleksandar Markovic         loaderparams.kernel_filename = kernel_filename;
11635298722eSAleksandar Markovic         loaderparams.kernel_cmdline = kernel_cmdline;
11645298722eSAleksandar Markovic         loaderparams.initrd_filename = initrd_filename;
11655298722eSAleksandar Markovic         kernel_entry = load_kernel();
11665298722eSAleksandar Markovic 
1167ac70f976SPhilippe Mathieu-Daudé         if (!cpu_type_supports_isa(machine->cpu_type, ISA_NANOMIPS32)) {
11685298722eSAleksandar Markovic             write_bootloader(memory_region_get_ram_ptr(bios),
11695298722eSAleksandar Markovic                              bootloader_run_addr, kernel_entry);
11705298722eSAleksandar Markovic         } else {
11715298722eSAleksandar Markovic             write_bootloader_nanomips(memory_region_get_ram_ptr(bios),
11725298722eSAleksandar Markovic                                       bootloader_run_addr, kernel_entry);
11735298722eSAleksandar Markovic         }
11745298722eSAleksandar Markovic     } else {
11755298722eSAleksandar Markovic         target_long bios_size = FLASH_SIZE;
11765298722eSAleksandar Markovic         /* Load firmware from flash. */
11775298722eSAleksandar Markovic         if (!dinfo) {
11785298722eSAleksandar Markovic             /* Load a BIOS image. */
1179a4374f86SPavel Dovgalyuk             filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
118059588beaSPaolo Bonzini                                       machine->firmware ?: BIOS_FILENAME);
11815298722eSAleksandar Markovic             if (filename) {
11825298722eSAleksandar Markovic                 bios_size = load_image_targphys(filename, FLASH_ADDRESS,
11835298722eSAleksandar Markovic                                                 BIOS_SIZE);
11845298722eSAleksandar Markovic                 g_free(filename);
11855298722eSAleksandar Markovic             } else {
11865298722eSAleksandar Markovic                 bios_size = -1;
11875298722eSAleksandar Markovic             }
11885298722eSAleksandar Markovic             if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
118959588beaSPaolo Bonzini                 machine->firmware && !qtest_enabled()) {
119059588beaSPaolo Bonzini                 error_report("Could not load MIPS bios '%s'", machine->firmware);
11915298722eSAleksandar Markovic                 exit(1);
11925298722eSAleksandar Markovic             }
11935298722eSAleksandar Markovic         }
11945298722eSAleksandar Markovic         /*
11955298722eSAleksandar Markovic          * In little endian mode the 32bit words in the bios are swapped,
11965298722eSAleksandar Markovic          * a neat trick which allows bi-endian firmware.
11975298722eSAleksandar Markovic          */
1198ee3eb3a7SMarc-André Lureau #if !TARGET_BIG_ENDIAN
11995298722eSAleksandar Markovic         {
12005298722eSAleksandar Markovic             uint32_t *end, *addr;
12015298722eSAleksandar Markovic             const size_t swapsize = MIN(bios_size, 0x3e0000);
12025298722eSAleksandar Markovic             addr = rom_ptr(FLASH_ADDRESS, swapsize);
12035298722eSAleksandar Markovic             if (!addr) {
12045298722eSAleksandar Markovic                 addr = memory_region_get_ram_ptr(bios);
12055298722eSAleksandar Markovic             }
12065298722eSAleksandar Markovic             end = (void *)addr + swapsize;
12075298722eSAleksandar Markovic             while (addr < end) {
12085298722eSAleksandar Markovic                 bswap32s(addr);
12095298722eSAleksandar Markovic                 addr++;
12105298722eSAleksandar Markovic             }
12115298722eSAleksandar Markovic         }
12125298722eSAleksandar Markovic #endif
12135298722eSAleksandar Markovic     }
12145298722eSAleksandar Markovic 
12155298722eSAleksandar Markovic     /*
12165298722eSAleksandar Markovic      * Map the BIOS at a 2nd physical location, as on the real board.
12175298722eSAleksandar Markovic      * Copy it so that we can patch in the MIPS revision, which cannot be
12185298722eSAleksandar Markovic      * handled by an overlapping region as the resulting ROM code subpage
12195298722eSAleksandar Markovic      * regions are not executable.
12205298722eSAleksandar Markovic      */
12215298722eSAleksandar Markovic     memory_region_init_ram(bios_copy, NULL, "bios.1fc", BIOS_SIZE,
12225298722eSAleksandar Markovic                            &error_fatal);
12235298722eSAleksandar Markovic     if (!rom_copy(memory_region_get_ram_ptr(bios_copy),
12245298722eSAleksandar Markovic                   FLASH_ADDRESS, BIOS_SIZE)) {
12255298722eSAleksandar Markovic         memcpy(memory_region_get_ram_ptr(bios_copy),
12265298722eSAleksandar Markovic                memory_region_get_ram_ptr(bios), BIOS_SIZE);
12275298722eSAleksandar Markovic     }
12285298722eSAleksandar Markovic     memory_region_set_readonly(bios_copy, true);
12295298722eSAleksandar Markovic     memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_copy);
12305298722eSAleksandar Markovic 
12315298722eSAleksandar Markovic     /* Board ID = 0x420 (Malta Board with CoreLV) */
12325298722eSAleksandar Markovic     stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420);
12335298722eSAleksandar Markovic 
12345298722eSAleksandar Markovic     /* Northbridge */
1235fae45dd5SPhilippe Mathieu-Daudé     dev = qdev_new("gt64120");
1236ded625e7SThomas Huth     qdev_prop_set_bit(dev, "cpu-little-endian", !TARGET_BIG_ENDIAN);
1237fae45dd5SPhilippe Mathieu-Daudé     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1238aa85a461SBernhard Beschow     pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci"));
12393c73d590SBernhard Beschow     pci_bus_map_irqs(pci_bus, malta_pci_slot_get_pirq);
12405298722eSAleksandar Markovic 
12415298722eSAleksandar Markovic     /* Southbridge */
12422922dbc2SBernhard Beschow     piix4 = pci_new_multifunction(PIIX4_PCI_DEVFN, TYPE_PIIX4_PCI_DEVICE);
12432922dbc2SBernhard Beschow     qdev_prop_set_uint32(DEVICE(piix4), "smb_io_base", 0x1100);
12442922dbc2SBernhard Beschow     pci_realize_and_unref(piix4, pci_bus, &error_fatal);
1245d240d3fbSBernhard Beschow     isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix4), "isa.0"));
1246d240d3fbSBernhard Beschow 
1247d240d3fbSBernhard Beschow     dev = DEVICE(object_resolve_path_component(OBJECT(piix4), "ide"));
1248d240d3fbSBernhard Beschow     pci_ide_create_devs(PCI_DEVICE(dev));
12495298722eSAleksandar Markovic 
12505298722eSAleksandar Markovic     /* Interrupt controller */
1251d240d3fbSBernhard Beschow     qdev_connect_gpio_out_named(DEVICE(piix4), "intr", 0, i8259_irq);
12525298722eSAleksandar Markovic 
12535298722eSAleksandar Markovic     /* generate SPD EEPROM data */
1254e5b6c3e2SBernhard Beschow     dev = DEVICE(object_resolve_path_component(OBJECT(piix4), "pm"));
1255e5b6c3e2SBernhard Beschow     smbus = I2C_BUS(qdev_get_child_bus(dev, "i2c"));
12565298722eSAleksandar Markovic     generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size);
12575298722eSAleksandar Markovic     generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
12585298722eSAleksandar Markovic     smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
12595298722eSAleksandar Markovic     g_free(smbus_eeprom_buf);
12605298722eSAleksandar Markovic 
12615298722eSAleksandar Markovic     /* Super I/O: SMS FDC37M817 */
12625298722eSAleksandar Markovic     isa_create_simple(isa_bus, TYPE_FDC37M81X_SUPERIO);
12635298722eSAleksandar Markovic 
12645298722eSAleksandar Markovic     /* Network card */
12655298722eSAleksandar Markovic     network_init(pci_bus);
12665298722eSAleksandar Markovic 
12675298722eSAleksandar Markovic     /* Optional PCI video card */
12685298722eSAleksandar Markovic     pci_vga_init(pci_bus);
12695298722eSAleksandar Markovic }
12705298722eSAleksandar Markovic 
mips_malta_instance_init(Object * obj)1271eea1f5baSPhilippe Mathieu-Daudé static void mips_malta_instance_init(Object *obj)
1272eea1f5baSPhilippe Mathieu-Daudé {
1273eea1f5baSPhilippe Mathieu-Daudé     MaltaState *s = MIPS_MALTA(obj);
1274eea1f5baSPhilippe Mathieu-Daudé 
1275eea1f5baSPhilippe Mathieu-Daudé     s->cpuclk = qdev_init_clock_out(DEVICE(obj), "cpu-refclk");
1276eea1f5baSPhilippe Mathieu-Daudé     clock_set_hz(s->cpuclk, 320000000); /* 320 MHz */
1277eea1f5baSPhilippe Mathieu-Daudé }
1278eea1f5baSPhilippe Mathieu-Daudé 
12795298722eSAleksandar Markovic static const TypeInfo mips_malta_device = {
12805298722eSAleksandar Markovic     .name          = TYPE_MIPS_MALTA,
12815298722eSAleksandar Markovic     .parent        = TYPE_SYS_BUS_DEVICE,
12825298722eSAleksandar Markovic     .instance_size = sizeof(MaltaState),
1283eea1f5baSPhilippe Mathieu-Daudé     .instance_init = mips_malta_instance_init,
12845298722eSAleksandar Markovic };
12855298722eSAleksandar Markovic 
1286bd64c210SIgor Mammedov GlobalProperty malta_compat[] = {
1287bd64c210SIgor Mammedov     { "PIIX4_PM", "memory-hotplug-support", "off" },
1288bd64c210SIgor Mammedov     { "PIIX4_PM", "acpi-pci-hotplug-with-bridge-support", "off" },
1289bd64c210SIgor Mammedov     { "PIIX4_PM", "acpi-root-pci-hotplug", "off" },
1290bd64c210SIgor Mammedov     { "PIIX4_PM", "x-not-migrate-acpi-index", "true" },
1291bd64c210SIgor Mammedov };
1292bd64c210SIgor Mammedov const size_t malta_compat_len = G_N_ELEMENTS(malta_compat);
1293bd64c210SIgor Mammedov 
mips_malta_machine_init(MachineClass * mc)12945298722eSAleksandar Markovic static void mips_malta_machine_init(MachineClass *mc)
12955298722eSAleksandar Markovic {
12965298722eSAleksandar Markovic     mc->desc = "MIPS Malta Core LV";
12975298722eSAleksandar Markovic     mc->init = mips_malta_init;
12985298722eSAleksandar Markovic     mc->block_default_type = IF_IDE;
12995298722eSAleksandar Markovic     mc->max_cpus = 16;
13005298722eSAleksandar Markovic     mc->is_default = true;
13015298722eSAleksandar Markovic #ifdef TARGET_MIPS64
13025298722eSAleksandar Markovic     mc->default_cpu_type = MIPS_CPU_TYPE_NAME("20Kc");
13035298722eSAleksandar Markovic #else
13045298722eSAleksandar Markovic     mc->default_cpu_type = MIPS_CPU_TYPE_NAME("24Kf");
13055298722eSAleksandar Markovic #endif
13065298722eSAleksandar Markovic     mc->default_ram_id = "mips_malta.ram";
1307bd64c210SIgor Mammedov     compat_props_add(mc->compat_props, malta_compat, malta_compat_len);
13085298722eSAleksandar Markovic }
13095298722eSAleksandar Markovic 
13105298722eSAleksandar Markovic DEFINE_MACHINE("malta", mips_malta_machine_init)
13115298722eSAleksandar Markovic 
mips_malta_register_types(void)13125298722eSAleksandar Markovic static void mips_malta_register_types(void)
13135298722eSAleksandar Markovic {
13145298722eSAleksandar Markovic     type_register_static(&mips_malta_device);
13155298722eSAleksandar Markovic }
13165298722eSAleksandar Markovic 
13175298722eSAleksandar Markovic type_init(mips_malta_register_types)
1318