Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 1 | /* |
| 2 | * MIPS Boston development board emulation. |
| 3 | * |
| 4 | * Copyright (c) 2016 Imagination Technologies |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
Chetan Pant | 4a129cc | 2020-10-23 12:26:33 +0000 | [diff] [blame] | 9 | * version 2.1 of the License, or (at your option) any later version. |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | |
| 20 | #include "qemu/osdep.h" |
Philippe Mathieu-Daudé | fc6b3cf | 2018-06-25 09:41:58 -0300 | [diff] [blame] | 21 | #include "qemu/units.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 22 | |
Jiaxun Yang | 10e3f30 | 2021-10-02 19:45:38 +0100 | [diff] [blame] | 23 | #include "elf.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 24 | #include "hw/boards.h" |
Bernhard Beschow | 7e6b549 | 2024-09-05 09:38:32 +0200 | [diff] [blame] | 25 | #include "hw/char/serial-mm.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 26 | #include "hw/ide/pci.h" |
Philippe Mathieu-Daudé | d407be0 | 2024-02-13 08:20:43 +0100 | [diff] [blame] | 27 | #include "hw/ide/ahci-pci.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 28 | #include "hw/loader.h" |
| 29 | #include "hw/loader-fit.h" |
Jiaxun Yang | 112658e | 2020-12-15 14:45:05 +0800 | [diff] [blame] | 30 | #include "hw/mips/bootloader.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 31 | #include "hw/mips/cps.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 32 | #include "hw/pci-host/xilinx-pcie.h" |
Philippe Mathieu-Daudé | 6b290b4 | 2020-10-12 11:58:01 +0200 | [diff] [blame] | 33 | #include "hw/qdev-clock.h" |
Markus Armbruster | a27bd6c | 2019-08-12 07:23:51 +0200 | [diff] [blame] | 34 | #include "hw/qdev-properties.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 35 | #include "qapi/error.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 36 | #include "qemu/error-report.h" |
Jason A. Donenfeld | 5e19cc6 | 2022-07-19 14:08:43 +0200 | [diff] [blame] | 37 | #include "qemu/guest-random.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 38 | #include "qemu/log.h" |
Marc-André Lureau | 8228e35 | 2017-01-26 17:19:46 +0400 | [diff] [blame] | 39 | #include "chardev/char.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 40 | #include "sysemu/device_tree.h" |
| 41 | #include "sysemu/sysemu.h" |
| 42 | #include "sysemu/qtest.h" |
Markus Armbruster | 54d3123 | 2019-08-12 07:23:59 +0200 | [diff] [blame] | 43 | #include "sysemu/runstate.h" |
Jason A. Donenfeld | 4fbae24 | 2022-10-25 02:43:24 +0200 | [diff] [blame] | 44 | #include "sysemu/reset.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 45 | |
| 46 | #include <libfdt.h> |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 47 | #include "qom/object.h" |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 48 | |
Eduardo Habkost | 27cf089 | 2020-09-02 18:42:26 -0400 | [diff] [blame] | 49 | #define TYPE_BOSTON "mips-boston" |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 50 | typedef struct BostonState BostonState; |
Eduardo Habkost | 8110fa1 | 2020-08-31 17:07:33 -0400 | [diff] [blame] | 51 | DECLARE_INSTANCE_CHECKER(BostonState, BOSTON, |
Eduardo Habkost | 27cf089 | 2020-09-02 18:42:26 -0400 | [diff] [blame] | 52 | TYPE_BOSTON) |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 53 | |
Jiaxun Yang | 7230389 | 2021-10-02 19:45:39 +0100 | [diff] [blame] | 54 | #define FDT_IRQ_TYPE_NONE 0 |
| 55 | #define FDT_IRQ_TYPE_LEVEL_HIGH 4 |
| 56 | #define FDT_GIC_SHARED 0 |
| 57 | #define FDT_GIC_LOCAL 1 |
| 58 | #define FDT_BOSTON_CLK_SYS 1 |
| 59 | #define FDT_BOSTON_CLK_CPU 2 |
| 60 | #define FDT_PCI_IRQ_MAP_PINS 4 |
| 61 | #define FDT_PCI_IRQ_MAP_DESCS 6 |
| 62 | |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 63 | struct BostonState { |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 64 | SysBusDevice parent_obj; |
| 65 | |
| 66 | MachineState *mach; |
Philippe Mathieu-Daudé | 2d5fac8 | 2019-05-07 18:34:09 +0200 | [diff] [blame] | 67 | MIPSCPSState cps; |
Marc-André Lureau | 490a9d9 | 2019-10-23 17:50:06 +0200 | [diff] [blame] | 68 | SerialMM *uart; |
Philippe Mathieu-Daudé | 6b290b4 | 2020-10-12 11:58:01 +0200 | [diff] [blame] | 69 | Clock *cpuclk; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 70 | |
| 71 | CharBackend lcd_display; |
| 72 | char lcd_content[8]; |
| 73 | bool lcd_inited; |
| 74 | |
| 75 | hwaddr kernel_entry; |
| 76 | hwaddr fdt_base; |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 77 | }; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 78 | |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 79 | enum { |
| 80 | BOSTON_LOWDDR, |
| 81 | BOSTON_PCIE0, |
| 82 | BOSTON_PCIE1, |
| 83 | BOSTON_PCIE2, |
| 84 | BOSTON_PCIE2_MMIO, |
| 85 | BOSTON_CM, |
| 86 | BOSTON_GIC, |
| 87 | BOSTON_CDMM, |
| 88 | BOSTON_CPC, |
| 89 | BOSTON_PLATREG, |
| 90 | BOSTON_UART, |
| 91 | BOSTON_LCD, |
| 92 | BOSTON_FLASH, |
| 93 | BOSTON_PCIE1_MMIO, |
| 94 | BOSTON_PCIE0_MMIO, |
| 95 | BOSTON_HIGHDDR, |
| 96 | }; |
| 97 | |
| 98 | static const MemMapEntry boston_memmap[] = { |
| 99 | [BOSTON_LOWDDR] = { 0x0, 0x10000000 }, |
| 100 | [BOSTON_PCIE0] = { 0x10000000, 0x2000000 }, |
| 101 | [BOSTON_PCIE1] = { 0x12000000, 0x2000000 }, |
| 102 | [BOSTON_PCIE2] = { 0x14000000, 0x2000000 }, |
| 103 | [BOSTON_PCIE2_MMIO] = { 0x16000000, 0x100000 }, |
| 104 | [BOSTON_CM] = { 0x16100000, 0x20000 }, |
| 105 | [BOSTON_GIC] = { 0x16120000, 0x20000 }, |
| 106 | [BOSTON_CDMM] = { 0x16140000, 0x8000 }, |
| 107 | [BOSTON_CPC] = { 0x16200000, 0x8000 }, |
| 108 | [BOSTON_PLATREG] = { 0x17ffd000, 0x1000 }, |
| 109 | [BOSTON_UART] = { 0x17ffe000, 0x20 }, |
| 110 | [BOSTON_LCD] = { 0x17fff000, 0x8 }, |
| 111 | [BOSTON_FLASH] = { 0x18000000, 0x8000000 }, |
| 112 | [BOSTON_PCIE1_MMIO] = { 0x20000000, 0x20000000 }, |
| 113 | [BOSTON_PCIE0_MMIO] = { 0x40000000, 0x40000000 }, |
| 114 | [BOSTON_HIGHDDR] = { 0x80000000, 0x0 }, |
| 115 | }; |
| 116 | |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 117 | enum boston_plat_reg { |
| 118 | PLAT_FPGA_BUILD = 0x00, |
| 119 | PLAT_CORE_CL = 0x04, |
| 120 | PLAT_WRAPPER_CL = 0x08, |
| 121 | PLAT_SYSCLK_STATUS = 0x0c, |
| 122 | PLAT_SOFTRST_CTL = 0x10, |
| 123 | #define PLAT_SOFTRST_CTL_SYSRESET (1 << 4) |
| 124 | PLAT_DDR3_STATUS = 0x14, |
| 125 | #define PLAT_DDR3_STATUS_LOCKED (1 << 0) |
| 126 | #define PLAT_DDR3_STATUS_CALIBRATED (1 << 2) |
| 127 | PLAT_PCIE_STATUS = 0x18, |
| 128 | #define PLAT_PCIE_STATUS_PCIE0_LOCKED (1 << 0) |
| 129 | #define PLAT_PCIE_STATUS_PCIE1_LOCKED (1 << 8) |
| 130 | #define PLAT_PCIE_STATUS_PCIE2_LOCKED (1 << 16) |
| 131 | PLAT_FLASH_CTL = 0x1c, |
| 132 | PLAT_SPARE0 = 0x20, |
| 133 | PLAT_SPARE1 = 0x24, |
| 134 | PLAT_SPARE2 = 0x28, |
| 135 | PLAT_SPARE3 = 0x2c, |
| 136 | PLAT_MMCM_DIV = 0x30, |
| 137 | #define PLAT_MMCM_DIV_CLK0DIV_SHIFT 0 |
| 138 | #define PLAT_MMCM_DIV_INPUT_SHIFT 8 |
| 139 | #define PLAT_MMCM_DIV_MUL_SHIFT 16 |
| 140 | #define PLAT_MMCM_DIV_CLK1DIV_SHIFT 24 |
| 141 | PLAT_BUILD_CFG = 0x34, |
| 142 | #define PLAT_BUILD_CFG_IOCU_EN (1 << 0) |
| 143 | #define PLAT_BUILD_CFG_PCIE0_EN (1 << 1) |
| 144 | #define PLAT_BUILD_CFG_PCIE1_EN (1 << 2) |
| 145 | #define PLAT_BUILD_CFG_PCIE2_EN (1 << 3) |
| 146 | PLAT_DDR_CFG = 0x38, |
| 147 | #define PLAT_DDR_CFG_SIZE (0xf << 0) |
| 148 | #define PLAT_DDR_CFG_MHZ (0xfff << 4) |
| 149 | PLAT_NOC_PCIE0_ADDR = 0x3c, |
| 150 | PLAT_NOC_PCIE1_ADDR = 0x40, |
| 151 | PLAT_NOC_PCIE2_ADDR = 0x44, |
| 152 | PLAT_SYS_CTL = 0x48, |
| 153 | }; |
| 154 | |
Philippe Mathieu-Daudé | 083b266 | 2019-12-18 18:20:09 +0100 | [diff] [blame] | 155 | static void boston_lcd_event(void *opaque, QEMUChrEvent event) |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 156 | { |
| 157 | BostonState *s = opaque; |
| 158 | if (event == CHR_EVENT_OPENED && !s->lcd_inited) { |
| 159 | qemu_chr_fe_printf(&s->lcd_display, " "); |
| 160 | s->lcd_inited = true; |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | static uint64_t boston_lcd_read(void *opaque, hwaddr addr, |
| 165 | unsigned size) |
| 166 | { |
| 167 | BostonState *s = opaque; |
| 168 | uint64_t val = 0; |
| 169 | |
| 170 | switch (size) { |
| 171 | case 8: |
| 172 | val |= (uint64_t)s->lcd_content[(addr + 7) & 0x7] << 56; |
| 173 | val |= (uint64_t)s->lcd_content[(addr + 6) & 0x7] << 48; |
| 174 | val |= (uint64_t)s->lcd_content[(addr + 5) & 0x7] << 40; |
| 175 | val |= (uint64_t)s->lcd_content[(addr + 4) & 0x7] << 32; |
| 176 | /* fall through */ |
| 177 | case 4: |
| 178 | val |= (uint64_t)s->lcd_content[(addr + 3) & 0x7] << 24; |
| 179 | val |= (uint64_t)s->lcd_content[(addr + 2) & 0x7] << 16; |
| 180 | /* fall through */ |
| 181 | case 2: |
| 182 | val |= (uint64_t)s->lcd_content[(addr + 1) & 0x7] << 8; |
| 183 | /* fall through */ |
| 184 | case 1: |
| 185 | val |= (uint64_t)s->lcd_content[(addr + 0) & 0x7]; |
| 186 | break; |
| 187 | } |
| 188 | |
| 189 | return val; |
| 190 | } |
| 191 | |
| 192 | static void boston_lcd_write(void *opaque, hwaddr addr, |
| 193 | uint64_t val, unsigned size) |
| 194 | { |
| 195 | BostonState *s = opaque; |
| 196 | |
| 197 | switch (size) { |
| 198 | case 8: |
| 199 | s->lcd_content[(addr + 7) & 0x7] = val >> 56; |
| 200 | s->lcd_content[(addr + 6) & 0x7] = val >> 48; |
| 201 | s->lcd_content[(addr + 5) & 0x7] = val >> 40; |
| 202 | s->lcd_content[(addr + 4) & 0x7] = val >> 32; |
| 203 | /* fall through */ |
| 204 | case 4: |
| 205 | s->lcd_content[(addr + 3) & 0x7] = val >> 24; |
| 206 | s->lcd_content[(addr + 2) & 0x7] = val >> 16; |
| 207 | /* fall through */ |
| 208 | case 2: |
| 209 | s->lcd_content[(addr + 1) & 0x7] = val >> 8; |
| 210 | /* fall through */ |
| 211 | case 1: |
| 212 | s->lcd_content[(addr + 0) & 0x7] = val; |
| 213 | break; |
| 214 | } |
| 215 | |
| 216 | qemu_chr_fe_printf(&s->lcd_display, |
| 217 | "\r%-8.8s", s->lcd_content); |
| 218 | } |
| 219 | |
| 220 | static const MemoryRegionOps boston_lcd_ops = { |
| 221 | .read = boston_lcd_read, |
| 222 | .write = boston_lcd_write, |
| 223 | .endianness = DEVICE_NATIVE_ENDIAN, |
| 224 | }; |
| 225 | |
| 226 | static uint64_t boston_platreg_read(void *opaque, hwaddr addr, |
| 227 | unsigned size) |
| 228 | { |
| 229 | BostonState *s = opaque; |
| 230 | uint32_t gic_freq, val; |
| 231 | |
| 232 | if (size != 4) { |
Philippe Mathieu-Daudé | c4c9883 | 2018-06-08 13:15:33 +0100 | [diff] [blame] | 233 | qemu_log_mask(LOG_UNIMP, "%uB platform register read\n", size); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 234 | return 0; |
| 235 | } |
| 236 | |
| 237 | switch (addr & 0xffff) { |
| 238 | case PLAT_FPGA_BUILD: |
| 239 | case PLAT_CORE_CL: |
| 240 | case PLAT_WRAPPER_CL: |
| 241 | return 0; |
| 242 | case PLAT_DDR3_STATUS: |
| 243 | return PLAT_DDR3_STATUS_LOCKED | PLAT_DDR3_STATUS_CALIBRATED; |
| 244 | case PLAT_MMCM_DIV: |
Philippe Mathieu-Daudé | 2d5fac8 | 2019-05-07 18:34:09 +0200 | [diff] [blame] | 245 | gic_freq = mips_gictimer_get_freq(s->cps.gic.gic_timer) / 1000000; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 246 | val = gic_freq << PLAT_MMCM_DIV_INPUT_SHIFT; |
| 247 | val |= 1 << PLAT_MMCM_DIV_MUL_SHIFT; |
| 248 | val |= 1 << PLAT_MMCM_DIV_CLK0DIV_SHIFT; |
| 249 | val |= 1 << PLAT_MMCM_DIV_CLK1DIV_SHIFT; |
| 250 | return val; |
| 251 | case PLAT_BUILD_CFG: |
| 252 | val = PLAT_BUILD_CFG_PCIE0_EN; |
| 253 | val |= PLAT_BUILD_CFG_PCIE1_EN; |
| 254 | val |= PLAT_BUILD_CFG_PCIE2_EN; |
| 255 | return val; |
| 256 | case PLAT_DDR_CFG: |
Philippe Mathieu-Daudé | d23b6ca | 2018-06-25 09:41:57 -0300 | [diff] [blame] | 257 | val = s->mach->ram_size / GiB; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 258 | assert(!(val & ~PLAT_DDR_CFG_SIZE)); |
| 259 | val |= PLAT_DDR_CFG_MHZ; |
| 260 | return val; |
| 261 | default: |
Philippe Mathieu-Daudé | c4c9883 | 2018-06-08 13:15:33 +0100 | [diff] [blame] | 262 | qemu_log_mask(LOG_UNIMP, "Read platform register 0x%" HWADDR_PRIx "\n", |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 263 | addr & 0xffff); |
| 264 | return 0; |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | static void boston_platreg_write(void *opaque, hwaddr addr, |
| 269 | uint64_t val, unsigned size) |
| 270 | { |
| 271 | if (size != 4) { |
Philippe Mathieu-Daudé | c4c9883 | 2018-06-08 13:15:33 +0100 | [diff] [blame] | 272 | qemu_log_mask(LOG_UNIMP, "%uB platform register write\n", size); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 273 | return; |
| 274 | } |
| 275 | |
| 276 | switch (addr & 0xffff) { |
| 277 | case PLAT_FPGA_BUILD: |
| 278 | case PLAT_CORE_CL: |
| 279 | case PLAT_WRAPPER_CL: |
| 280 | case PLAT_DDR3_STATUS: |
| 281 | case PLAT_PCIE_STATUS: |
| 282 | case PLAT_MMCM_DIV: |
| 283 | case PLAT_BUILD_CFG: |
| 284 | case PLAT_DDR_CFG: |
| 285 | /* read only */ |
| 286 | break; |
| 287 | case PLAT_SOFTRST_CTL: |
| 288 | if (val & PLAT_SOFTRST_CTL_SYSRESET) { |
Eric Blake | cf83f14 | 2017-05-15 16:41:13 -0500 | [diff] [blame] | 289 | qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 290 | } |
| 291 | break; |
| 292 | default: |
| 293 | qemu_log_mask(LOG_UNIMP, "Write platform register 0x%" HWADDR_PRIx |
Philippe Mathieu-Daudé | c4c9883 | 2018-06-08 13:15:33 +0100 | [diff] [blame] | 294 | " = 0x%" PRIx64 "\n", addr & 0xffff, val); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 295 | break; |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | static const MemoryRegionOps boston_platreg_ops = { |
| 300 | .read = boston_platreg_read, |
| 301 | .write = boston_platreg_write, |
| 302 | .endianness = DEVICE_NATIVE_ENDIAN, |
| 303 | }; |
| 304 | |
Philippe Mathieu-Daudé | 6b290b4 | 2020-10-12 11:58:01 +0200 | [diff] [blame] | 305 | static void mips_boston_instance_init(Object *obj) |
| 306 | { |
| 307 | BostonState *s = BOSTON(obj); |
| 308 | |
| 309 | s->cpuclk = qdev_init_clock_out(DEVICE(obj), "cpu-refclk"); |
| 310 | clock_set_hz(s->cpuclk, 1000000000); /* 1 GHz */ |
| 311 | } |
| 312 | |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 313 | static const TypeInfo boston_device = { |
Eduardo Habkost | 27cf089 | 2020-09-02 18:42:26 -0400 | [diff] [blame] | 314 | .name = TYPE_BOSTON, |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 315 | .parent = TYPE_SYS_BUS_DEVICE, |
| 316 | .instance_size = sizeof(BostonState), |
Philippe Mathieu-Daudé | 6b290b4 | 2020-10-12 11:58:01 +0200 | [diff] [blame] | 317 | .instance_init = mips_boston_instance_init, |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 318 | }; |
| 319 | |
| 320 | static void boston_register_types(void) |
| 321 | { |
| 322 | type_register_static(&boston_device); |
| 323 | } |
| 324 | type_init(boston_register_types) |
| 325 | |
Philippe Mathieu-Daudé | cd5066f | 2022-11-02 16:24:39 +0100 | [diff] [blame] | 326 | static void gen_firmware(void *p, hwaddr kernel_entry, hwaddr fdt_addr) |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 327 | { |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 328 | uint64_t regaddr; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 329 | |
| 330 | /* Move CM GCRs */ |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 331 | regaddr = cpu_mips_phys_to_kseg1(NULL, GCR_BASE_ADDR + GCR_BASE_OFS), |
| 332 | bl_gen_write_ulong(&p, regaddr, |
| 333 | boston_memmap[BOSTON_CM].base); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 334 | |
| 335 | /* Move & enable GIC GCRs */ |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 336 | regaddr = cpu_mips_phys_to_kseg1(NULL, boston_memmap[BOSTON_CM].base |
| 337 | + GCR_GIC_BASE_OFS), |
| 338 | bl_gen_write_ulong(&p, regaddr, |
| 339 | boston_memmap[BOSTON_GIC].base | GCR_GIC_BASE_GICEN_MSK); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 340 | |
| 341 | /* Move & enable CPC GCRs */ |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 342 | regaddr = cpu_mips_phys_to_kseg1(NULL, boston_memmap[BOSTON_CM].base |
| 343 | + GCR_CPC_BASE_OFS), |
| 344 | bl_gen_write_ulong(&p, regaddr, |
| 345 | boston_memmap[BOSTON_CPC].base | GCR_CPC_BASE_CPCEN_MSK); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 346 | |
| 347 | /* |
| 348 | * Setup argument registers to follow the UHI boot protocol: |
| 349 | * |
| 350 | * a0/$4 = -2 |
| 351 | * a1/$5 = virtual address of FDT |
| 352 | * a2/$6 = 0 |
| 353 | * a3/$7 = 0 |
| 354 | */ |
Philippe Mathieu-Daudé | 36d7487 | 2022-10-26 21:18:19 +0200 | [diff] [blame] | 355 | bl_gen_jump_kernel(&p, |
| 356 | true, 0, true, (int32_t)-2, |
| 357 | true, fdt_addr, true, 0, true, 0, |
| 358 | kernel_entry); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 359 | } |
| 360 | |
| 361 | static const void *boston_fdt_filter(void *opaque, const void *fdt_orig, |
| 362 | const void *match_data, hwaddr *load_addr) |
| 363 | { |
| 364 | BostonState *s = BOSTON(opaque); |
| 365 | MachineState *machine = s->mach; |
| 366 | const char *cmdline; |
| 367 | int err; |
Peter Maydell | bf4ee88 | 2020-11-06 17:58:23 +0000 | [diff] [blame] | 368 | size_t ram_low_sz, ram_high_sz; |
| 369 | size_t fdt_sz = fdt_totalsize(fdt_orig) * 2; |
| 370 | g_autofree void *fdt = g_malloc0(fdt_sz); |
Jason A. Donenfeld | 5e19cc6 | 2022-07-19 14:08:43 +0200 | [diff] [blame] | 371 | uint8_t rng_seed[32]; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 372 | |
| 373 | err = fdt_open_into(fdt_orig, fdt, fdt_sz); |
| 374 | if (err) { |
| 375 | fprintf(stderr, "unable to open FDT\n"); |
| 376 | return NULL; |
| 377 | } |
| 378 | |
Jason A. Donenfeld | 5e19cc6 | 2022-07-19 14:08:43 +0200 | [diff] [blame] | 379 | qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); |
| 380 | qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); |
| 381 | |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 382 | cmdline = (machine->kernel_cmdline && machine->kernel_cmdline[0]) |
| 383 | ? machine->kernel_cmdline : " "; |
| 384 | err = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); |
| 385 | if (err < 0) { |
| 386 | fprintf(stderr, "couldn't set /chosen/bootargs\n"); |
| 387 | return NULL; |
| 388 | } |
| 389 | |
Philippe Mathieu-Daudé | d23b6ca | 2018-06-25 09:41:57 -0300 | [diff] [blame] | 390 | ram_low_sz = MIN(256 * MiB, machine->ram_size); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 391 | ram_high_sz = machine->ram_size - ram_low_sz; |
| 392 | qemu_fdt_setprop_sized_cells(fdt, "/memory@0", "reg", |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 393 | 1, boston_memmap[BOSTON_LOWDDR].base, 1, ram_low_sz, |
| 394 | 1, boston_memmap[BOSTON_HIGHDDR].base + ram_low_sz, |
| 395 | 1, ram_high_sz); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 396 | |
| 397 | fdt = g_realloc(fdt, fdt_totalsize(fdt)); |
| 398 | qemu_fdt_dumpdtb(fdt, fdt_sz); |
| 399 | |
| 400 | s->fdt_base = *load_addr; |
| 401 | |
Peter Maydell | bf4ee88 | 2020-11-06 17:58:23 +0000 | [diff] [blame] | 402 | return g_steal_pointer(&fdt); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 403 | } |
| 404 | |
| 405 | static const void *boston_kernel_filter(void *opaque, const void *kernel, |
| 406 | hwaddr *load_addr, hwaddr *entry_addr) |
| 407 | { |
| 408 | BostonState *s = BOSTON(opaque); |
| 409 | |
| 410 | s->kernel_entry = *entry_addr; |
| 411 | |
| 412 | return kernel; |
| 413 | } |
| 414 | |
| 415 | static const struct fit_loader_match boston_matches[] = { |
| 416 | { "img,boston" }, |
| 417 | { NULL }, |
| 418 | }; |
| 419 | |
| 420 | static const struct fit_loader boston_fit_loader = { |
| 421 | .matches = boston_matches, |
| 422 | .addr_to_phys = cpu_mips_kseg0_to_phys, |
| 423 | .fdt_filter = boston_fdt_filter, |
| 424 | .kernel_filter = boston_kernel_filter, |
| 425 | }; |
| 426 | |
| 427 | static inline XilinxPCIEHost * |
| 428 | xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr, |
| 429 | hwaddr cfg_base, uint64_t cfg_size, |
| 430 | hwaddr mmio_base, uint64_t mmio_size, |
Jiaxun Yang | 3c43fc3 | 2022-10-24 15:35:40 +0100 | [diff] [blame] | 431 | qemu_irq irq) |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 432 | { |
| 433 | DeviceState *dev; |
| 434 | MemoryRegion *cfg, *mmio; |
| 435 | |
Markus Armbruster | 3e80f69 | 2020-06-10 07:31:58 +0200 | [diff] [blame] | 436 | dev = qdev_new(TYPE_XILINX_PCIE_HOST); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 437 | |
| 438 | qdev_prop_set_uint32(dev, "bus_nr", bus_nr); |
| 439 | qdev_prop_set_uint64(dev, "cfg_base", cfg_base); |
| 440 | qdev_prop_set_uint64(dev, "cfg_size", cfg_size); |
| 441 | qdev_prop_set_uint64(dev, "mmio_base", mmio_base); |
| 442 | qdev_prop_set_uint64(dev, "mmio_size", mmio_size); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 443 | |
Markus Armbruster | 3c6ef47 | 2020-06-10 07:32:34 +0200 | [diff] [blame] | 444 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 445 | |
| 446 | cfg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); |
| 447 | memory_region_add_subregion_overlap(sys_mem, cfg_base, cfg, 0); |
| 448 | |
| 449 | mmio = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); |
| 450 | memory_region_add_subregion_overlap(sys_mem, 0, mmio, 0); |
| 451 | |
| 452 | qdev_connect_gpio_out_named(dev, "interrupt_out", 0, irq); |
| 453 | |
| 454 | return XILINX_PCIE_HOST(dev); |
| 455 | } |
| 456 | |
Jiaxun Yang | 7230389 | 2021-10-02 19:45:39 +0100 | [diff] [blame] | 457 | |
| 458 | static void fdt_create_pcie(void *fdt, int gic_ph, int irq, hwaddr reg_base, |
| 459 | hwaddr reg_size, hwaddr mmio_base, hwaddr mmio_size) |
| 460 | { |
| 461 | int i; |
| 462 | char *name, *intc_name; |
| 463 | uint32_t intc_ph; |
| 464 | uint32_t interrupt_map[FDT_PCI_IRQ_MAP_PINS][FDT_PCI_IRQ_MAP_DESCS]; |
| 465 | |
| 466 | intc_ph = qemu_fdt_alloc_phandle(fdt); |
| 467 | name = g_strdup_printf("/soc/pci@%" HWADDR_PRIx, reg_base); |
| 468 | qemu_fdt_add_subnode(fdt, name); |
| 469 | qemu_fdt_setprop_string(fdt, name, "compatible", |
| 470 | "xlnx,axi-pcie-host-1.00.a"); |
| 471 | qemu_fdt_setprop_string(fdt, name, "device_type", "pci"); |
| 472 | qemu_fdt_setprop_cells(fdt, name, "reg", reg_base, reg_size); |
| 473 | |
| 474 | qemu_fdt_setprop_cell(fdt, name, "#address-cells", 3); |
| 475 | qemu_fdt_setprop_cell(fdt, name, "#size-cells", 2); |
| 476 | qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 1); |
| 477 | |
| 478 | qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", gic_ph); |
| 479 | qemu_fdt_setprop_cells(fdt, name, "interrupts", FDT_GIC_SHARED, irq, |
| 480 | FDT_IRQ_TYPE_LEVEL_HIGH); |
| 481 | |
| 482 | qemu_fdt_setprop_cells(fdt, name, "ranges", 0x02000000, 0, mmio_base, |
| 483 | mmio_base, 0, mmio_size); |
| 484 | qemu_fdt_setprop_cells(fdt, name, "bus-range", 0x00, 0xff); |
| 485 | |
| 486 | |
| 487 | |
| 488 | intc_name = g_strdup_printf("%s/interrupt-controller", name); |
| 489 | qemu_fdt_add_subnode(fdt, intc_name); |
| 490 | qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0); |
| 491 | qemu_fdt_setprop_cell(fdt, intc_name, "#address-cells", 0); |
| 492 | qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1); |
| 493 | qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_ph); |
| 494 | |
| 495 | qemu_fdt_setprop_cells(fdt, name, "interrupt-map-mask", 0, 0, 0, 7); |
| 496 | for (i = 0; i < FDT_PCI_IRQ_MAP_PINS; i++) { |
| 497 | uint32_t *irqmap = interrupt_map[i]; |
| 498 | |
| 499 | irqmap[0] = cpu_to_be32(0); |
| 500 | irqmap[1] = cpu_to_be32(0); |
| 501 | irqmap[2] = cpu_to_be32(0); |
| 502 | irqmap[3] = cpu_to_be32(i + 1); |
| 503 | irqmap[4] = cpu_to_be32(intc_ph); |
| 504 | irqmap[5] = cpu_to_be32(i + 1); |
| 505 | } |
| 506 | qemu_fdt_setprop(fdt, name, "interrupt-map", |
| 507 | &interrupt_map, sizeof(interrupt_map)); |
| 508 | |
| 509 | g_free(intc_name); |
| 510 | g_free(name); |
| 511 | } |
| 512 | |
| 513 | static const void *create_fdt(BostonState *s, |
| 514 | const MemMapEntry *memmap, int *dt_size) |
| 515 | { |
| 516 | void *fdt; |
| 517 | int cpu; |
Daniel Henrique Barboza | 0263346 | 2023-01-11 14:21:33 -0300 | [diff] [blame] | 518 | MachineState *ms = s->mach; |
Jiaxun Yang | 7230389 | 2021-10-02 19:45:39 +0100 | [diff] [blame] | 519 | uint32_t platreg_ph, gic_ph, clk_ph; |
| 520 | char *name, *gic_name, *platreg_name, *stdout_name; |
| 521 | static const char * const syscon_compat[2] = { |
| 522 | "img,boston-platform-regs", "syscon" |
| 523 | }; |
| 524 | |
| 525 | fdt = create_device_tree(dt_size); |
| 526 | if (!fdt) { |
| 527 | error_report("create_device_tree() failed"); |
| 528 | exit(1); |
| 529 | } |
| 530 | |
| 531 | platreg_ph = qemu_fdt_alloc_phandle(fdt); |
| 532 | gic_ph = qemu_fdt_alloc_phandle(fdt); |
| 533 | clk_ph = qemu_fdt_alloc_phandle(fdt); |
| 534 | |
| 535 | qemu_fdt_setprop_string(fdt, "/", "model", "img,boston"); |
| 536 | qemu_fdt_setprop_string(fdt, "/", "compatible", "img,boston"); |
| 537 | qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1); |
| 538 | qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x1); |
| 539 | |
| 540 | |
| 541 | qemu_fdt_add_subnode(fdt, "/cpus"); |
| 542 | qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0); |
| 543 | qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); |
| 544 | |
Daniel Henrique Barboza | 0263346 | 2023-01-11 14:21:33 -0300 | [diff] [blame] | 545 | for (cpu = 0; cpu < ms->smp.cpus; cpu++) { |
Jiaxun Yang | 7230389 | 2021-10-02 19:45:39 +0100 | [diff] [blame] | 546 | name = g_strdup_printf("/cpus/cpu@%d", cpu); |
| 547 | qemu_fdt_add_subnode(fdt, name); |
| 548 | qemu_fdt_setprop_string(fdt, name, "compatible", "img,mips"); |
| 549 | qemu_fdt_setprop_string(fdt, name, "status", "okay"); |
| 550 | qemu_fdt_setprop_cell(fdt, name, "reg", cpu); |
| 551 | qemu_fdt_setprop_string(fdt, name, "device_type", "cpu"); |
| 552 | qemu_fdt_setprop_cells(fdt, name, "clocks", clk_ph, FDT_BOSTON_CLK_CPU); |
| 553 | g_free(name); |
| 554 | } |
| 555 | |
| 556 | qemu_fdt_add_subnode(fdt, "/soc"); |
| 557 | qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0); |
| 558 | qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus"); |
| 559 | qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1); |
| 560 | qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x1); |
| 561 | |
| 562 | fdt_create_pcie(fdt, gic_ph, 2, |
| 563 | memmap[BOSTON_PCIE0].base, memmap[BOSTON_PCIE0].size, |
| 564 | memmap[BOSTON_PCIE0_MMIO].base, memmap[BOSTON_PCIE0_MMIO].size); |
| 565 | |
| 566 | fdt_create_pcie(fdt, gic_ph, 1, |
| 567 | memmap[BOSTON_PCIE1].base, memmap[BOSTON_PCIE1].size, |
| 568 | memmap[BOSTON_PCIE1_MMIO].base, memmap[BOSTON_PCIE1_MMIO].size); |
| 569 | |
| 570 | fdt_create_pcie(fdt, gic_ph, 0, |
| 571 | memmap[BOSTON_PCIE2].base, memmap[BOSTON_PCIE2].size, |
| 572 | memmap[BOSTON_PCIE2_MMIO].base, memmap[BOSTON_PCIE2_MMIO].size); |
| 573 | |
| 574 | /* GIC with it's timer node */ |
| 575 | gic_name = g_strdup_printf("/soc/interrupt-controller@%" HWADDR_PRIx, |
| 576 | memmap[BOSTON_GIC].base); |
| 577 | qemu_fdt_add_subnode(fdt, gic_name); |
| 578 | qemu_fdt_setprop_string(fdt, gic_name, "compatible", "mti,gic"); |
| 579 | qemu_fdt_setprop_cells(fdt, gic_name, "reg", memmap[BOSTON_GIC].base, |
| 580 | memmap[BOSTON_GIC].size); |
| 581 | qemu_fdt_setprop(fdt, gic_name, "interrupt-controller", NULL, 0); |
| 582 | qemu_fdt_setprop_cell(fdt, gic_name, "#interrupt-cells", 3); |
| 583 | qemu_fdt_setprop_cell(fdt, gic_name, "phandle", gic_ph); |
| 584 | |
| 585 | name = g_strdup_printf("%s/timer", gic_name); |
| 586 | qemu_fdt_add_subnode(fdt, name); |
| 587 | qemu_fdt_setprop_string(fdt, name, "compatible", "mti,gic-timer"); |
| 588 | qemu_fdt_setprop_cells(fdt, name, "interrupts", FDT_GIC_LOCAL, 1, |
| 589 | FDT_IRQ_TYPE_NONE); |
| 590 | qemu_fdt_setprop_cells(fdt, name, "clocks", clk_ph, FDT_BOSTON_CLK_CPU); |
| 591 | g_free(name); |
| 592 | g_free(gic_name); |
| 593 | |
| 594 | /* CDMM node */ |
| 595 | name = g_strdup_printf("/soc/cdmm@%" HWADDR_PRIx, memmap[BOSTON_CDMM].base); |
| 596 | qemu_fdt_add_subnode(fdt, name); |
| 597 | qemu_fdt_setprop_string(fdt, name, "compatible", "mti,mips-cdmm"); |
| 598 | qemu_fdt_setprop_cells(fdt, name, "reg", memmap[BOSTON_CDMM].base, |
| 599 | memmap[BOSTON_CDMM].size); |
| 600 | g_free(name); |
| 601 | |
| 602 | /* CPC node */ |
| 603 | name = g_strdup_printf("/soc/cpc@%" HWADDR_PRIx, memmap[BOSTON_CPC].base); |
| 604 | qemu_fdt_add_subnode(fdt, name); |
| 605 | qemu_fdt_setprop_string(fdt, name, "compatible", "mti,mips-cpc"); |
| 606 | qemu_fdt_setprop_cells(fdt, name, "reg", memmap[BOSTON_CPC].base, |
| 607 | memmap[BOSTON_CPC].size); |
| 608 | g_free(name); |
| 609 | |
| 610 | /* platreg and it's clk node */ |
| 611 | platreg_name = g_strdup_printf("/soc/system-controller@%" HWADDR_PRIx, |
| 612 | memmap[BOSTON_PLATREG].base); |
| 613 | qemu_fdt_add_subnode(fdt, platreg_name); |
| 614 | qemu_fdt_setprop_string_array(fdt, platreg_name, "compatible", |
| 615 | (char **)&syscon_compat, |
| 616 | ARRAY_SIZE(syscon_compat)); |
| 617 | qemu_fdt_setprop_cells(fdt, platreg_name, "reg", |
| 618 | memmap[BOSTON_PLATREG].base, |
| 619 | memmap[BOSTON_PLATREG].size); |
| 620 | qemu_fdt_setprop_cell(fdt, platreg_name, "phandle", platreg_ph); |
| 621 | |
| 622 | name = g_strdup_printf("%s/clock", platreg_name); |
| 623 | qemu_fdt_add_subnode(fdt, name); |
| 624 | qemu_fdt_setprop_string(fdt, name, "compatible", "img,boston-clock"); |
| 625 | qemu_fdt_setprop_cell(fdt, name, "#clock-cells", 1); |
| 626 | qemu_fdt_setprop_cell(fdt, name, "phandle", clk_ph); |
| 627 | g_free(name); |
| 628 | g_free(platreg_name); |
| 629 | |
| 630 | /* reboot node */ |
| 631 | name = g_strdup_printf("/soc/reboot"); |
| 632 | qemu_fdt_add_subnode(fdt, name); |
| 633 | qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-reboot"); |
| 634 | qemu_fdt_setprop_cell(fdt, name, "regmap", platreg_ph); |
| 635 | qemu_fdt_setprop_cell(fdt, name, "offset", 0x10); |
| 636 | qemu_fdt_setprop_cell(fdt, name, "mask", 0x10); |
| 637 | g_free(name); |
| 638 | |
| 639 | /* uart node */ |
| 640 | name = g_strdup_printf("/soc/uart@%" HWADDR_PRIx, memmap[BOSTON_UART].base); |
| 641 | qemu_fdt_add_subnode(fdt, name); |
| 642 | qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a"); |
| 643 | qemu_fdt_setprop_cells(fdt, name, "reg", memmap[BOSTON_UART].base, |
| 644 | memmap[BOSTON_UART].size); |
| 645 | qemu_fdt_setprop_cell(fdt, name, "reg-shift", 0x2); |
| 646 | qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", gic_ph); |
| 647 | qemu_fdt_setprop_cells(fdt, name, "interrupts", FDT_GIC_SHARED, 3, |
| 648 | FDT_IRQ_TYPE_LEVEL_HIGH); |
| 649 | qemu_fdt_setprop_cells(fdt, name, "clocks", clk_ph, FDT_BOSTON_CLK_SYS); |
| 650 | |
| 651 | qemu_fdt_add_subnode(fdt, "/chosen"); |
| 652 | stdout_name = g_strdup_printf("%s:115200", name); |
| 653 | qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", stdout_name); |
| 654 | g_free(stdout_name); |
| 655 | g_free(name); |
| 656 | |
| 657 | /* lcd node */ |
| 658 | name = g_strdup_printf("/soc/lcd@%" HWADDR_PRIx, memmap[BOSTON_LCD].base); |
| 659 | qemu_fdt_add_subnode(fdt, name); |
| 660 | qemu_fdt_setprop_string(fdt, name, "compatible", "img,boston-lcd"); |
| 661 | qemu_fdt_setprop_cells(fdt, name, "reg", memmap[BOSTON_LCD].base, |
| 662 | memmap[BOSTON_LCD].size); |
| 663 | g_free(name); |
| 664 | |
| 665 | name = g_strdup_printf("/memory@0"); |
| 666 | qemu_fdt_add_subnode(fdt, name); |
| 667 | qemu_fdt_setprop_string(fdt, name, "device_type", "memory"); |
| 668 | g_free(name); |
| 669 | |
| 670 | return fdt; |
| 671 | } |
| 672 | |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 673 | static void boston_mach_init(MachineState *machine) |
| 674 | { |
| 675 | DeviceState *dev; |
| 676 | BostonState *s; |
Igor Mammedov | 9389d6c | 2020-02-19 11:09:24 -0500 | [diff] [blame] | 677 | MemoryRegion *flash, *ddr_low_alias, *lcd, *platreg; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 678 | MemoryRegion *sys_mem = get_system_memory(); |
| 679 | XilinxPCIEHost *pcie2; |
Philippe Mathieu-Daudé | 41c05b4 | 2024-02-13 08:30:00 +0100 | [diff] [blame] | 680 | PCIDevice *pdev; |
Philippe Mathieu-Daudé | e6097f1 | 2024-02-13 08:31:45 +0100 | [diff] [blame] | 681 | AHCIPCIState *ich9; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 682 | DriveInfo *hd[6]; |
| 683 | Chardev *chr; |
| 684 | int fw_size, fit_err; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 685 | |
Philippe Mathieu-Daudé | d23b6ca | 2018-06-25 09:41:57 -0300 | [diff] [blame] | 686 | if ((machine->ram_size % GiB) || |
| 687 | (machine->ram_size > (2 * GiB))) { |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 688 | error_report("Memory size must be 1GB or 2GB"); |
| 689 | exit(1); |
| 690 | } |
| 691 | |
Eduardo Habkost | 27cf089 | 2020-09-02 18:42:26 -0400 | [diff] [blame] | 692 | dev = qdev_new(TYPE_BOSTON); |
Markus Armbruster | 3c6ef47 | 2020-06-10 07:32:34 +0200 | [diff] [blame] | 693 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 694 | |
| 695 | s = BOSTON(dev); |
| 696 | s->mach = machine; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 697 | |
Philippe Mathieu-Daudé | ac70f97 | 2020-12-07 22:32:49 +0100 | [diff] [blame] | 698 | if (!cpu_type_supports_cps_smp(machine->cpu_type)) { |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 699 | error_report("Boston requires CPUs which support CPS"); |
| 700 | exit(1); |
| 701 | } |
| 702 | |
Markus Armbruster | 0074fce | 2020-06-10 07:32:36 +0200 | [diff] [blame] | 703 | object_initialize_child(OBJECT(machine), "cps", &s->cps, TYPE_MIPS_CPS); |
Markus Armbruster | 5325cc3 | 2020-07-07 18:05:54 +0200 | [diff] [blame] | 704 | object_property_set_str(OBJECT(&s->cps), "cpu-type", machine->cpu_type, |
Markus Armbruster | 932d3a6 | 2020-05-05 12:19:05 +0200 | [diff] [blame] | 705 | &error_fatal); |
Philippe Mathieu-Daudé | 10997f2 | 2023-02-02 10:46:45 +0100 | [diff] [blame] | 706 | object_property_set_uint(OBJECT(&s->cps), "num-vp", machine->smp.cpus, |
Markus Armbruster | 932d3a6 | 2020-05-05 12:19:05 +0200 | [diff] [blame] | 707 | &error_fatal); |
Philippe Mathieu-Daudé | 6b290b4 | 2020-10-12 11:58:01 +0200 | [diff] [blame] | 708 | qdev_connect_clock_in(DEVICE(&s->cps), "clk-in", |
| 709 | qdev_get_clock_out(dev, "cpu-refclk")); |
Markus Armbruster | 0074fce | 2020-06-10 07:32:36 +0200 | [diff] [blame] | 710 | sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 711 | |
Philippe Mathieu-Daudé | 2d5fac8 | 2019-05-07 18:34:09 +0200 | [diff] [blame] | 712 | sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 713 | |
| 714 | flash = g_new(MemoryRegion, 1); |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 715 | memory_region_init_rom(flash, NULL, "boston.flash", |
| 716 | boston_memmap[BOSTON_FLASH].size, &error_fatal); |
| 717 | memory_region_add_subregion_overlap(sys_mem, |
| 718 | boston_memmap[BOSTON_FLASH].base, |
| 719 | flash, 0); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 720 | |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 721 | memory_region_add_subregion_overlap(sys_mem, |
| 722 | boston_memmap[BOSTON_HIGHDDR].base, |
| 723 | machine->ram, 0); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 724 | |
| 725 | ddr_low_alias = g_new(MemoryRegion, 1); |
| 726 | memory_region_init_alias(ddr_low_alias, NULL, "boston_low.ddr", |
Igor Mammedov | 9389d6c | 2020-02-19 11:09:24 -0500 | [diff] [blame] | 727 | machine->ram, 0, |
| 728 | MIN(machine->ram_size, (256 * MiB))); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 729 | memory_region_add_subregion_overlap(sys_mem, 0, ddr_low_alias, 0); |
| 730 | |
| 731 | xilinx_pcie_init(sys_mem, 0, |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 732 | boston_memmap[BOSTON_PCIE0].base, |
| 733 | boston_memmap[BOSTON_PCIE0].size, |
| 734 | boston_memmap[BOSTON_PCIE0_MMIO].base, |
| 735 | boston_memmap[BOSTON_PCIE0_MMIO].size, |
Jiaxun Yang | 3c43fc3 | 2022-10-24 15:35:40 +0100 | [diff] [blame] | 736 | get_cps_irq(&s->cps, 2)); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 737 | |
| 738 | xilinx_pcie_init(sys_mem, 1, |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 739 | boston_memmap[BOSTON_PCIE1].base, |
| 740 | boston_memmap[BOSTON_PCIE1].size, |
| 741 | boston_memmap[BOSTON_PCIE1_MMIO].base, |
| 742 | boston_memmap[BOSTON_PCIE1_MMIO].size, |
Jiaxun Yang | 3c43fc3 | 2022-10-24 15:35:40 +0100 | [diff] [blame] | 743 | get_cps_irq(&s->cps, 1)); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 744 | |
| 745 | pcie2 = xilinx_pcie_init(sys_mem, 2, |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 746 | boston_memmap[BOSTON_PCIE2].base, |
| 747 | boston_memmap[BOSTON_PCIE2].size, |
| 748 | boston_memmap[BOSTON_PCIE2_MMIO].base, |
| 749 | boston_memmap[BOSTON_PCIE2_MMIO].size, |
Jiaxun Yang | 3c43fc3 | 2022-10-24 15:35:40 +0100 | [diff] [blame] | 750 | get_cps_irq(&s->cps, 0)); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 751 | |
| 752 | platreg = g_new(MemoryRegion, 1); |
| 753 | memory_region_init_io(platreg, NULL, &boston_platreg_ops, s, |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 754 | "boston-platregs", |
| 755 | boston_memmap[BOSTON_PLATREG].size); |
| 756 | memory_region_add_subregion_overlap(sys_mem, |
| 757 | boston_memmap[BOSTON_PLATREG].base, platreg, 0); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 758 | |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 759 | s->uart = serial_mm_init(sys_mem, boston_memmap[BOSTON_UART].base, 2, |
Philippe Mathieu-Daudé | 2d5fac8 | 2019-05-07 18:34:09 +0200 | [diff] [blame] | 760 | get_cps_irq(&s->cps, 3), 10000000, |
Peter Maydell | 9bca0ed | 2018-04-20 15:52:43 +0100 | [diff] [blame] | 761 | serial_hd(0), DEVICE_NATIVE_ENDIAN); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 762 | |
| 763 | lcd = g_new(MemoryRegion, 1); |
| 764 | memory_region_init_io(lcd, NULL, &boston_lcd_ops, s, "boston-lcd", 0x8); |
Jiaxun Yang | e07f3e2 | 2021-10-02 19:45:37 +0100 | [diff] [blame] | 765 | memory_region_add_subregion_overlap(sys_mem, |
| 766 | boston_memmap[BOSTON_LCD].base, lcd, 0); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 767 | |
Paolo Bonzini | 4ad6f6c | 2019-02-13 14:18:13 +0100 | [diff] [blame] | 768 | chr = qemu_chr_new("lcd", "vc:320x240", NULL); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 769 | qemu_chr_fe_init(&s->lcd_display, chr, NULL); |
| 770 | qemu_chr_fe_set_handlers(&s->lcd_display, NULL, NULL, |
Anton Nefedov | 81517ba | 2017-07-06 15:08:49 +0300 | [diff] [blame] | 771 | boston_lcd_event, NULL, s, NULL, true); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 772 | |
Philippe Mathieu-Daudé | 41c05b4 | 2024-02-13 08:30:00 +0100 | [diff] [blame] | 773 | pdev = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus, |
Bernhard Beschow | e052944 | 2023-03-04 12:40:42 +0100 | [diff] [blame] | 774 | PCI_DEVFN(0, 0), TYPE_ICH9_AHCI); |
Philippe Mathieu-Daudé | e6097f1 | 2024-02-13 08:31:45 +0100 | [diff] [blame] | 775 | ich9 = ICH9_AHCI(pdev); |
| 776 | g_assert(ARRAY_SIZE(hd) == ich9->ahci.ports); |
| 777 | ide_drive_get(hd, ich9->ahci.ports); |
Philippe Mathieu-Daudé | e2f8d28 | 2024-02-13 08:34:27 +0100 | [diff] [blame] | 778 | ahci_ide_create_devs(&ich9->ahci, hd); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 779 | |
| 780 | if (machine->firmware) { |
| 781 | fw_size = load_image_targphys(machine->firmware, |
Philippe Mathieu-Daudé | d23b6ca | 2018-06-25 09:41:57 -0300 | [diff] [blame] | 782 | 0x1fc00000, 4 * MiB); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 783 | if (fw_size == -1) { |
Markus Armbruster | 036a260 | 2019-04-17 21:06:30 +0200 | [diff] [blame] | 784 | error_report("unable to load firmware image '%s'", |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 785 | machine->firmware); |
| 786 | exit(1); |
| 787 | } |
| 788 | } else if (machine->kernel_filename) { |
Jiaxun Yang | d77c462 | 2021-11-30 21:17:29 +0000 | [diff] [blame] | 789 | uint64_t kernel_entry, kernel_high; |
| 790 | ssize_t kernel_size; |
Jiaxun Yang | 10e3f30 | 2021-10-02 19:45:38 +0100 | [diff] [blame] | 791 | |
| 792 | kernel_size = load_elf(machine->kernel_filename, NULL, |
| 793 | cpu_mips_kseg0_to_phys, NULL, |
| 794 | &kernel_entry, NULL, &kernel_high, |
| 795 | NULL, 0, EM_MIPS, 1, 0); |
| 796 | |
Jiaxun Yang | d77c462 | 2021-11-30 21:17:29 +0000 | [diff] [blame] | 797 | if (kernel_size > 0) { |
Jiaxun Yang | 7230389 | 2021-10-02 19:45:39 +0100 | [diff] [blame] | 798 | int dt_size; |
Bernhard Beschow | b1f66fa | 2022-06-05 17:19:08 +0200 | [diff] [blame] | 799 | g_autofree const void *dtb_file_data = NULL; |
| 800 | g_autofree const void *dtb_load_data = NULL; |
Jiaxun Yang | 10e3f30 | 2021-10-02 19:45:38 +0100 | [diff] [blame] | 801 | hwaddr dtb_paddr = QEMU_ALIGN_UP(kernel_high, 64 * KiB); |
| 802 | hwaddr dtb_vaddr = cpu_mips_phys_to_kseg0(NULL, dtb_paddr); |
| 803 | |
| 804 | s->kernel_entry = kernel_entry; |
| 805 | if (machine->dtb) { |
Jiaxun Yang | 10e3f30 | 2021-10-02 19:45:38 +0100 | [diff] [blame] | 806 | dtb_file_data = load_device_tree(machine->dtb, &dt_size); |
Jiaxun Yang | 7230389 | 2021-10-02 19:45:39 +0100 | [diff] [blame] | 807 | } else { |
| 808 | dtb_file_data = create_fdt(s, boston_memmap, &dt_size); |
Jiaxun Yang | 10e3f30 | 2021-10-02 19:45:38 +0100 | [diff] [blame] | 809 | } |
Jiaxun Yang | 7230389 | 2021-10-02 19:45:39 +0100 | [diff] [blame] | 810 | |
| 811 | dtb_load_data = boston_fdt_filter(s, dtb_file_data, |
| 812 | NULL, &dtb_vaddr); |
| 813 | |
| 814 | /* Calculate real fdt size after filter */ |
| 815 | dt_size = fdt_totalsize(dtb_load_data); |
| 816 | rom_add_blob_fixed("dtb", dtb_load_data, dt_size, dtb_paddr); |
Jason A. Donenfeld | 4fbae24 | 2022-10-25 02:43:24 +0200 | [diff] [blame] | 817 | qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, |
| 818 | rom_ptr(dtb_paddr, dt_size)); |
Jiaxun Yang | 10e3f30 | 2021-10-02 19:45:38 +0100 | [diff] [blame] | 819 | } else { |
| 820 | /* Try to load file as FIT */ |
| 821 | fit_err = load_fit(&boston_fit_loader, machine->kernel_filename, s); |
| 822 | if (fit_err) { |
| 823 | error_report("unable to load kernel image"); |
| 824 | exit(1); |
| 825 | } |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 826 | } |
| 827 | |
| 828 | gen_firmware(memory_region_get_ram_ptr(flash) + 0x7c00000, |
Jiaxun Yang | 283eae1 | 2021-01-27 14:54:24 +0800 | [diff] [blame] | 829 | s->kernel_entry, s->fdt_base); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 830 | } else if (!qtest_enabled()) { |
Markus Armbruster | 036a260 | 2019-04-17 21:06:30 +0200 | [diff] [blame] | 831 | error_report("Please provide either a -kernel or -bios argument"); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 832 | exit(1); |
| 833 | } |
| 834 | } |
| 835 | |
| 836 | static void boston_mach_class_init(MachineClass *mc) |
| 837 | { |
| 838 | mc->desc = "MIPS Boston"; |
| 839 | mc->init = boston_mach_init; |
| 840 | mc->block_default_type = IF_IDE; |
Philippe Mathieu-Daudé | d23b6ca | 2018-06-25 09:41:57 -0300 | [diff] [blame] | 841 | mc->default_ram_size = 1 * GiB; |
Igor Mammedov | 9389d6c | 2020-02-19 11:09:24 -0500 | [diff] [blame] | 842 | mc->default_ram_id = "boston.ddr"; |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 843 | mc->max_cpus = 16; |
Igor Mammedov | a7519f2 | 2017-10-05 15:51:10 +0200 | [diff] [blame] | 844 | mc->default_cpu_type = MIPS_CPU_TYPE_NAME("I6400"); |
Paul Burton | df1d8a1 | 2016-09-08 15:51:58 +0100 | [diff] [blame] | 845 | } |
| 846 | |
| 847 | DEFINE_MACHINE("boston", boston_mach_class_init) |