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