]>
Commit | Line | Data |
---|---|---|
9c6d57dc SG |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Bootmethod for QEMU qfw | |
4 | * | |
5 | * Copyright 2023 Google LLC | |
6 | * Written by Simon Glass <[email protected]> | |
7 | */ | |
8 | ||
9 | #define LOG_CATEGORY UCLASS_BOOTSTD | |
10 | ||
d678a59d | 11 | #include <common.h> |
9c6d57dc SG |
12 | #include <command.h> |
13 | #include <bootdev.h> | |
14 | #include <bootflow.h> | |
15 | #include <bootmeth.h> | |
16 | #include <env.h> | |
17 | #include <qfw.h> | |
18 | #include <dm.h> | |
19 | ||
20 | static int qfw_check(struct udevice *dev, struct bootflow_iter *iter) | |
21 | { | |
22 | const struct udevice *media = dev_get_parent(iter->dev); | |
23 | enum uclass_id id = device_get_uclass_id(media); | |
24 | ||
25 | log_debug("media=%s\n", media->name); | |
26 | if (id == UCLASS_QFW) | |
27 | return 0; | |
28 | ||
29 | return -ENOTSUPP; | |
30 | } | |
31 | ||
32 | static int qfw_read_bootflow(struct udevice *dev, struct bootflow *bflow) | |
33 | { | |
34 | struct udevice *qfw_dev = dev_get_parent(bflow->dev); | |
35 | ulong load, initrd; | |
36 | int ret; | |
37 | ||
38 | load = env_get_hex("kernel_addr_r", 0); | |
39 | initrd = env_get_hex("ramdisk_addr_r", 0); | |
40 | log_debug("setup kernel %s %lx %lx\n", qfw_dev->name, load, initrd); | |
41 | bflow->name = strdup("qfw"); | |
42 | if (!bflow->name) | |
43 | return log_msg_ret("name", -ENOMEM); | |
44 | ||
45 | ret = qemu_fwcfg_setup_kernel(qfw_dev, load, initrd); | |
46 | log_debug("setup kernel result %d\n", ret); | |
47 | if (ret) | |
48 | return log_msg_ret("cmd", -EIO); | |
49 | ||
50 | bflow->state = BOOTFLOWST_READY; | |
51 | ||
52 | return 0; | |
53 | } | |
54 | ||
55 | static int qfw_read_file(struct udevice *dev, struct bootflow *bflow, | |
56 | const char *file_path, ulong addr, ulong *sizep) | |
57 | { | |
58 | return -ENOSYS; | |
59 | } | |
60 | ||
61 | static int qfw_boot(struct udevice *dev, struct bootflow *bflow) | |
62 | { | |
63 | int ret; | |
64 | ||
65 | ret = run_command("booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdtcontroladdr}", | |
66 | 0); | |
67 | if (ret) { | |
68 | ret = run_command("bootz ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} " | |
69 | "${fdtcontroladdr}", 0); | |
70 | } | |
71 | ||
72 | return ret ? -EIO : 0; | |
73 | } | |
74 | ||
75 | static int qfw_bootmeth_bind(struct udevice *dev) | |
76 | { | |
77 | struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); | |
78 | ||
3c2e531c | 79 | plat->desc = "QEMU boot using firmware interface"; |
9c6d57dc SG |
80 | |
81 | return 0; | |
82 | } | |
83 | ||
84 | static struct bootmeth_ops qfw_bootmeth_ops = { | |
85 | .check = qfw_check, | |
86 | .read_bootflow = qfw_read_bootflow, | |
87 | .read_file = qfw_read_file, | |
88 | .boot = qfw_boot, | |
89 | }; | |
90 | ||
91 | static const struct udevice_id qfw_bootmeth_ids[] = { | |
79f66351 | 92 | { .compatible = "u-boot,qfw-extlinux" }, |
9c6d57dc SG |
93 | { } |
94 | }; | |
95 | ||
96 | U_BOOT_DRIVER(bootmeth_qfw) = { | |
97 | .name = "bootmeth_qfw", | |
98 | .id = UCLASS_BOOTMETH, | |
99 | .of_match = qfw_bootmeth_ids, | |
100 | .ops = &qfw_bootmeth_ops, | |
101 | .bind = qfw_bootmeth_bind, | |
102 | }; |