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