1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Read a bootflow from SPI flash
4 *
5 * Copyright 2022 Google LLC
6 */
7
8 #include <common.h>
9 #include <bootdev.h>
10 #include <bootflow.h>
11 #include <bootmeth.h>
12 #include <dm.h>
13 #include <env.h>
14 #include <malloc.h>
15 #include <spi_flash.h>
16
sf_get_bootflow(struct udevice * dev,struct bootflow_iter * iter,struct bootflow * bflow)17 static int sf_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
18 struct bootflow *bflow)
19 {
20 struct udevice *sf = dev_get_parent(dev);
21 uint size;
22 char *buf;
23 int ret;
24
25 /* We only support the whole device, not partitions */
26 if (iter->part)
27 return log_msg_ret("max", -ESHUTDOWN);
28
29 size = env_get_hex("script_size_f", 0);
30 if (!size)
31 return log_msg_ret("sz", -EINVAL);
32
33 buf = malloc(size + 1);
34 if (!buf)
35 return log_msg_ret("buf", -ENOMEM);
36
37 ret = spi_flash_read_dm(sf, env_get_hex("script_offset_f", 0),
38 size, buf);
39 if (ret)
40 return log_msg_ret("cmd", -EINVAL);
41 bflow->state = BOOTFLOWST_MEDIA;
42
43 ret = bootmeth_set_bootflow(bflow->method, bflow, buf, size);
44 if (ret) {
45 free(buf);
46 return log_msg_ret("method", ret);
47 }
48
49 return 0;
50 }
51
sf_bootdev_bind(struct udevice * dev)52 static int sf_bootdev_bind(struct udevice *dev)
53 {
54 struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
55
56 ucp->prio = BOOTDEVP_4_SCAN_FAST;
57
58 return 0;
59 }
60
61 struct bootdev_ops sf_bootdev_ops = {
62 .get_bootflow = sf_get_bootflow,
63 };
64
65 static const struct udevice_id sf_bootdev_ids[] = {
66 { .compatible = "u-boot,bootdev-sf" },
67 { }
68 };
69
70 U_BOOT_DRIVER(sf_bootdev) = {
71 .name = "sf_bootdev",
72 .id = UCLASS_BOOTDEV,
73 .ops = &sf_bootdev_ops,
74 .bind = sf_bootdev_bind,
75 .of_match = sf_bootdev_ids,
76 };
77
78 BOOTDEV_HUNTER(sf_bootdev_hunter) = {
79 .prio = BOOTDEVP_4_SCAN_FAST,
80 .uclass = UCLASS_SPI_FLASH,
81 .drv = DM_DRIVER_REF(sf_bootdev),
82 };
83