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