blob: 4fa903b8f3a47aa75b5303e7f346366c3eb833b4 [file] [log] [blame]
Caleb Connollyb55c0f82023-12-07 00:13:07 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Common initialisation for Qualcomm Snapdragon boards.
4 *
5 * Copyright (c) 2023 Linaro Ltd.
6 * Author: Caleb Connolly <caleb.connolly@linaro.org>
7 */
8
9#define LOG_DEBUG
10
11#include <dm/device.h>
12#include <efi.h>
13#include <efi_loader.h>
14#include <malloc.h>
15#include <scsi.h>
16#include <part.h>
17
18#include "qcom-priv.h"
19
20struct efi_fw_image fw_images[] = {
21 {
22 .image_type_id = QUALCOMM_UBOOT_BOOT_IMAGE_GUID,
23 .fw_name = u"QUALCOMM-UBOOT",
24 .image_index = 1,
25 },
26};
27
28struct efi_capsule_update_info update_info = {
29 /* Filled in by configure_dfu_string() */
30 .dfu_string = NULL,
31 .num_images = ARRAY_SIZE(fw_images),
32 .images = fw_images,
33};
34
35/**
36 * out_len includes the trailing null space
37 */
38static int get_cmdline_option(const char *cmdline, const char *key, char *out, int out_len)
39{
40 const char *p, *p_end;
41 int len;
42
43 p = strstr(cmdline, key);
44 if (!p)
45 return -ENOENT;
46
47 p += strlen(key);
48 p_end = strstr(p, " ");
49 if (!p_end)
50 return -ENOENT;
51
52 len = p_end - p;
53 if (len > out_len)
54 len = out_len;
55
56 strncpy(out, p, len);
57 out[len] = '\0';
58
59 return 0;
60}
61
62/* The bootargs are populated by the previous stage bootloader */
63static const char *get_cmdline(void)
64{
65 ofnode node;
66 static const char *cmdline = NULL;
67
68 if (cmdline)
69 return cmdline;
70
71 node = ofnode_path("/chosen");
72 if (!ofnode_valid(node))
73 return NULL;
74
75 cmdline = ofnode_read_string(node, "bootargs");
76
77 return cmdline;
78}
79
80static int find_boot_partition(const char *partname, struct blk_desc *blk_dev, struct disk_partition *info)
81{
82 int ret;
83 int partnum;
84
85 for (partnum = 1;; partnum++) {
86 ret = part_get_info(blk_dev, partnum, info);
87 if (ret) {
88 return ret;
89 }
90 if (!strncmp(info->name, partname, 6)) {
91 return partnum;
92 }
93 }
94
95 return 0;
96}
97
98/**
99 * qcom_configure_capsule_updates() - Configure the DFU string for capsule updates
100 *
101 * U-Boot is flashed to the boot partition on Qualcomm boards. In most cases there
102 * are two boot partitions, boot_a and boot_b. As we don't currently support doing
103 * full A/B updates, we only support updating the currently active boot partition.
104 *
105 * So we need to find the current slot suffix and the associated boot partition.
106 * The slot suffix is most easily accessed via the bootargs which are populated by
107 * the previous stage bootloader (ABL). However in the future we will likely want to
108 * read them directly from the GPT vendor attribute bits.
109 *
110 * For now only SCSI is supported.
111 */
112void qcom_configure_capsule_updates(void)
113{
114 struct blk_desc *desc;
115 struct disk_partition info;
116 int ret, partnum = -1, devnum;
117 char *dfu_string;
118 const char *cmdline;
119 char partname[7] = "boot";
120
121#ifdef CONFIG_DM_SCSI
122 /* Scan for SCSI devices */
123 ret = scsi_scan(false);
124 if (ret) {
125 debug("Failed to scan SCSI devices: %d\n", ret);
126 return;
127 }
128#else
129 debug("Qualcomm UEFI CapsuleUpdates requires SCSI support\n");
130 return;
131#endif
132
133 cmdline = get_cmdline();
134 if (!cmdline) {
135 debug("Failed to get bootargs\n");
136 return;
137 }
138
139 /* Some boards might only have one boot partition, so this is optional */
140 ret = get_cmdline_option(cmdline, "androidboot.slot_suffix=", &partname[4], 3);
141 if (ret < 0)
142 debug("Failed to get slot suffix from bootargs (board might be A-only?)\n");
143
144 for(devnum = 0;; devnum++) {
145 ret = blk_get_desc(UCLASS_SCSI, devnum, &desc);
146 if (ret == -ENODEV)
147 break;
148 else if (ret)
149 continue;
150 if (desc->part_type != PART_TYPE_UNKNOWN) {
151 partnum = find_boot_partition(partname, desc, &info);
152 if (partnum >= 0)
153 break;
154 }
155 }
156 if (partnum < 0) {
157 debug("Failed to find boot partition\n");
158 return;
159 }
160
161 dfu_string = malloc(32);
162
163 snprintf(dfu_string, 32, "scsi %d=u-boot-bin part %d", devnum, partnum);
164 printf("DFU string: %s\n", dfu_string);
165
166 update_info.dfu_string = dfu_string;
167}