config: enable TPS65219 for am64x_evm_a53 boards
[platform/kernel/u-boot.git] / boot / bootmeth_distro.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Bootmethod for distro boot (syslinux boot from a block device)
4  *
5  * Copyright 2021 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8
9 #define LOG_CATEGORY UCLASS_BOOTSTD
10
11 #include <common.h>
12 #include <bootdev.h>
13 #include <bootflow.h>
14 #include <bootmeth.h>
15 #include <bootstd.h>
16 #include <command.h>
17 #include <distro.h>
18 #include <dm.h>
19 #include <fs.h>
20 #include <malloc.h>
21 #include <mapmem.h>
22 #include <mmc.h>
23 #include <pxe_utils.h>
24
25 static int disto_getfile(struct pxe_context *ctx, const char *file_path,
26                          char *file_addr, ulong *sizep)
27 {
28         struct distro_info *info = ctx->userdata;
29         ulong addr;
30         int ret;
31
32         addr = simple_strtoul(file_addr, NULL, 16);
33
34         /* Allow up to 1GB */
35         *sizep = 1 << 30;
36         ret = bootmeth_read_file(info->dev, info->bflow, file_path, addr,
37                                  sizep);
38         if (ret)
39                 return log_msg_ret("read", ret);
40
41         return 0;
42 }
43
44 static int distro_check(struct udevice *dev, struct bootflow_iter *iter)
45 {
46         int ret;
47
48         /* This only works on block devices */
49         ret = bootflow_iter_uses_blk_dev(iter);
50         if (ret)
51                 return log_msg_ret("blk", ret);
52
53         return 0;
54 }
55
56 static int distro_read_bootflow(struct udevice *dev, struct bootflow *bflow)
57 {
58         struct blk_desc *desc;
59         const char *const *prefixes;
60         struct udevice *bootstd;
61         const char *prefix;
62         loff_t size;
63         int ret, i;
64
65         ret = uclass_first_device_err(UCLASS_BOOTSTD, &bootstd);
66         if (ret)
67                 return log_msg_ret("std", ret);
68
69         /* If a block device, we require a partition table */
70         if (bflow->blk && !bflow->part)
71                 return -ENOENT;
72
73         prefixes = bootstd_get_prefixes(bootstd);
74         i = 0;
75         desc = bflow->blk ? dev_get_uclass_plat(bflow->blk) : NULL;
76         do {
77                 prefix = prefixes ? prefixes[i] : NULL;
78
79                 ret = bootmeth_try_file(bflow, desc, prefix, DISTRO_FNAME);
80         } while (ret && prefixes && prefixes[++i]);
81         if (ret)
82                 return log_msg_ret("try", ret);
83         size = bflow->size;
84
85         ret = bootmeth_alloc_file(bflow, 0x10000, 1);
86         if (ret)
87                 return log_msg_ret("read", ret);
88
89         return 0;
90 }
91
92 static int distro_boot(struct udevice *dev, struct bootflow *bflow)
93 {
94         struct cmd_tbl cmdtp = {};      /* dummy */
95         struct pxe_context ctx;
96         struct distro_info info;
97         ulong addr;
98         int ret;
99
100         addr = map_to_sysmem(bflow->buf);
101         info.dev = dev;
102         info.bflow = bflow;
103         ret = pxe_setup_ctx(&ctx, &cmdtp, disto_getfile, &info, true,
104                             bflow->subdir);
105         if (ret)
106                 return log_msg_ret("ctx", -EINVAL);
107
108         ret = pxe_process(&ctx, addr, false);
109         if (ret)
110                 return log_msg_ret("bread", -EINVAL);
111
112         return 0;
113 }
114
115 static int distro_bootmeth_bind(struct udevice *dev)
116 {
117         struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
118
119         plat->desc = IS_ENABLED(CONFIG_BOOTSTD_FULL) ?
120                 "Syslinux boot from a block device" : "syslinux";
121
122         return 0;
123 }
124
125 static struct bootmeth_ops distro_bootmeth_ops = {
126         .check          = distro_check,
127         .read_bootflow  = distro_read_bootflow,
128         .read_file      = bootmeth_common_read_file,
129         .boot           = distro_boot,
130 };
131
132 static const struct udevice_id distro_bootmeth_ids[] = {
133         { .compatible = "u-boot,distro-syslinux" },
134         { }
135 };
136
137 U_BOOT_DRIVER(bootmeth_distro) = {
138         .name           = "bootmeth_distro",
139         .id             = UCLASS_BOOTMETH,
140         .of_match       = distro_bootmeth_ids,
141         .ops            = &distro_bootmeth_ops,
142         .bind           = distro_bootmeth_bind,
143 };