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