1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/reboot.h> 4 #include <linux/serial_core.h> 5 #include <linux/random.h> 6 #include <clocksource/timer-goldfish.h> 7 8 #include <asm/bootinfo.h> 9 #include <asm/bootinfo-virt.h> 10 #include <asm/byteorder.h> 11 #include <asm/machdep.h> 12 #include <asm/virt.h> 13 #include <asm/config.h> 14 15 struct virt_booter_data virt_bi_data; 16 17 #define VIRT_CTRL_REG_FEATURES 0x00 18 #define VIRT_CTRL_REG_CMD 0x04 19 20 static struct resource ctrlres; 21 22 enum { 23 CMD_NOOP, 24 CMD_RESET, 25 CMD_HALT, 26 CMD_PANIC, 27 }; 28 29 static void virt_get_model(char *str) 30 { 31 /* str is 80 characters long */ 32 sprintf(str, "QEMU Virtual M68K Machine (%u.%u.%u)", 33 (u8)(virt_bi_data.qemu_version >> 24), 34 (u8)(virt_bi_data.qemu_version >> 16), 35 (u8)(virt_bi_data.qemu_version >> 8)); 36 } 37 38 static void virt_halt(void) 39 { 40 void __iomem *base = (void __iomem *)virt_bi_data.ctrl.mmio; 41 42 iowrite32be(CMD_HALT, base + VIRT_CTRL_REG_CMD); 43 local_irq_disable(); 44 while (1) 45 ; 46 } 47 48 static void virt_reset(void) 49 { 50 void __iomem *base = (void __iomem *)virt_bi_data.ctrl.mmio; 51 52 iowrite32be(CMD_RESET, base + VIRT_CTRL_REG_CMD); 53 local_irq_disable(); 54 while (1) 55 ; 56 } 57 58 /* 59 * Parse a virtual-m68k-specific record in the bootinfo 60 */ 61 62 int __init virt_parse_bootinfo(const struct bi_record *record) 63 { 64 int unknown = 0; 65 const void *data = record->data; 66 67 switch (be16_to_cpu(record->tag)) { 68 case BI_VIRT_QEMU_VERSION: 69 virt_bi_data.qemu_version = be32_to_cpup(data); 70 break; 71 case BI_VIRT_GF_PIC_BASE: 72 virt_bi_data.pic.mmio = be32_to_cpup(data); 73 data += 4; 74 virt_bi_data.pic.irq = be32_to_cpup(data); 75 break; 76 case BI_VIRT_GF_RTC_BASE: 77 virt_bi_data.rtc.mmio = be32_to_cpup(data); 78 data += 4; 79 virt_bi_data.rtc.irq = be32_to_cpup(data); 80 break; 81 case BI_VIRT_GF_TTY_BASE: 82 virt_bi_data.tty.mmio = be32_to_cpup(data); 83 data += 4; 84 virt_bi_data.tty.irq = be32_to_cpup(data); 85 break; 86 case BI_VIRT_CTRL_BASE: 87 virt_bi_data.ctrl.mmio = be32_to_cpup(data); 88 data += 4; 89 virt_bi_data.ctrl.irq = be32_to_cpup(data); 90 break; 91 case BI_VIRT_VIRTIO_BASE: 92 virt_bi_data.virtio.mmio = be32_to_cpup(data); 93 data += 4; 94 virt_bi_data.virtio.irq = be32_to_cpup(data); 95 break; 96 case BI_VIRT_RNG_SEED: { 97 u16 len = be16_to_cpup(data); 98 add_bootloader_randomness(data + 2, len); 99 /* 100 * Zero the data to preserve forward secrecy, and zero the 101 * length to prevent kexec from using it. 102 */ 103 memzero_explicit((void *)data, len + 2); 104 break; 105 } 106 default: 107 unknown = 1; 108 break; 109 } 110 return unknown; 111 } 112 113 static void __init virt_sched_init(void) 114 { 115 goldfish_timer_init(virt_bi_data.rtc.irq, 116 (void __iomem *)virt_bi_data.rtc.mmio); 117 } 118 119 void __init config_virt(void) 120 { 121 char earlycon[24]; 122 123 snprintf(earlycon, sizeof(earlycon), "early_gf_tty,0x%08x", 124 virt_bi_data.tty.mmio); 125 setup_earlycon(earlycon); 126 127 ctrlres = (struct resource) 128 DEFINE_RES_MEM_NAMED(virt_bi_data.ctrl.mmio, 0x100, 129 "virtctrl"); 130 131 if (request_resource(&iomem_resource, &ctrlres)) { 132 pr_err("Cannot allocate virt controller resource\n"); 133 return; 134 } 135 136 mach_init_IRQ = virt_init_IRQ; 137 mach_sched_init = virt_sched_init; 138 mach_get_model = virt_get_model; 139 mach_reset = virt_reset; 140 mach_halt = virt_halt; 141 142 register_platform_power_off(virt_halt); 143 } 144