]>
Commit | Line | Data |
---|---|---|
ec2933e5 PD |
1 | // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause |
2 | /* | |
3 | * Copyright (C) 2020, STMicroelectronics - All Rights Reserved | |
4 | */ | |
5 | ||
6 | #include <common.h> | |
31325e1b | 7 | #include <blk.h> |
a00867b4 | 8 | #include <dm.h> |
ec2933e5 PD |
9 | #include <dfu.h> |
10 | #include <env.h> | |
11 | #include <memalign.h> | |
12 | #include <misc.h> | |
13 | #include <mtd.h> | |
14 | #include <mtd_node.h> | |
954bd1a9 | 15 | #include <asm/arch/stm32prog.h> |
ec2933e5 PD |
16 | |
17 | #define DFU_ALT_BUF_LEN SZ_1K | |
18 | ||
31325e1b | 19 | static void board_get_alt_info_mmc(struct udevice *dev, char *buf) |
ec2933e5 | 20 | { |
0528979f | 21 | struct disk_partition info; |
31325e1b PD |
22 | int p, len, devnum; |
23 | bool first = true; | |
24 | const char *name; | |
25 | struct mmc *mmc; | |
26 | struct blk_desc *desc; | |
27 | ||
28 | mmc = mmc_get_mmc_dev(dev); | |
29 | if (!mmc) | |
30 | return; | |
31 | ||
32 | if (mmc_init(mmc)) | |
33 | return; | |
34 | ||
35 | desc = mmc_get_blk_desc(mmc); | |
36 | if (!desc) | |
37 | return; | |
38 | ||
39 | name = blk_get_if_type_name(desc->if_type); | |
40 | devnum = desc->devnum; | |
41 | len = strlen(buf); | |
42 | ||
43 | if (buf[0] != '\0') | |
44 | len += snprintf(buf + len, | |
45 | DFU_ALT_BUF_LEN - len, "&"); | |
46 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, | |
47 | "%s %d=", name, devnum); | |
48 | ||
49 | if (IS_MMC(mmc) && mmc->capacity_boot) { | |
50 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, | |
51 | "%s%d_boot1 raw 0x0 0x%llx mmcpart 1;", | |
52 | name, devnum, mmc->capacity_boot); | |
53 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, | |
54 | "%s%d_boot2 raw 0x0 0x%llx mmcpart 2", | |
55 | name, devnum, mmc->capacity_boot); | |
56 | first = false; | |
57 | } | |
ec2933e5 | 58 | |
31325e1b PD |
59 | for (p = 1; p < MAX_SEARCH_PARTITIONS; p++) { |
60 | if (part_get_info(desc, p, &info)) | |
61 | continue; | |
62 | if (!first) | |
63 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, ";"); | |
64 | first = false; | |
65 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, | |
66 | "%s%d_%s part %d %d", | |
67 | name, devnum, info.name, devnum, p); | |
68 | } | |
69 | } | |
ec2933e5 | 70 | |
31325e1b PD |
71 | static void board_get_alt_info_mtd(struct mtd_info *mtd, char *buf) |
72 | { | |
73 | struct mtd_info *part; | |
74 | bool first = true; | |
75 | const char *name; | |
76 | int len, partnum = 0; | |
77 | ||
78 | name = mtd->name; | |
79 | len = strlen(buf); | |
80 | ||
81 | if (buf[0] != '\0') | |
82 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "&"); | |
83 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, | |
84 | "mtd %s=", name); | |
85 | ||
86 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, | |
87 | "%s raw 0x0 0x%llx ", | |
88 | name, mtd->size); | |
89 | ||
90 | list_for_each_entry(part, &mtd->partitions, node) { | |
91 | partnum++; | |
92 | if (!first) | |
93 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, ";"); | |
94 | first = false; | |
95 | ||
96 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, | |
97 | "%s_%s part %d", | |
98 | name, part->name, partnum); | |
ec2933e5 PD |
99 | } |
100 | } | |
101 | ||
102 | void set_dfu_alt_info(char *interface, char *devstr) | |
103 | { | |
104 | struct udevice *dev; | |
105 | struct mtd_info *mtd; | |
106 | ||
107 | ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); | |
108 | ||
109 | if (env_get("dfu_alt_info")) | |
110 | return; | |
111 | ||
112 | memset(buf, 0, sizeof(buf)); | |
113 | ||
31325e1b PD |
114 | snprintf(buf, DFU_ALT_BUF_LEN, |
115 | "ram 0=%s", CONFIG_DFU_ALT_RAM0); | |
ec2933e5 | 116 | |
75f9b190 PD |
117 | if (CONFIG_IS_ENABLED(MMC)) { |
118 | if (!uclass_get_device(UCLASS_MMC, 0, &dev)) | |
119 | board_get_alt_info_mmc(dev, buf); | |
ec2933e5 | 120 | |
75f9b190 PD |
121 | if (!uclass_get_device(UCLASS_MMC, 1, &dev)) |
122 | board_get_alt_info_mmc(dev, buf); | |
123 | } | |
31325e1b PD |
124 | |
125 | if (CONFIG_IS_ENABLED(MTD)) { | |
126 | /* probe all MTD devices */ | |
127 | mtd_probe_devices(); | |
128 | ||
129 | /* probe SPI flash device on a bus */ | |
130 | if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev)) { | |
131 | mtd = get_mtd_device_nm("nor0"); | |
132 | if (!IS_ERR_OR_NULL(mtd)) | |
133 | board_get_alt_info_mtd(mtd, buf); | |
134 | } | |
135 | ||
136 | mtd = get_mtd_device_nm("nand0"); | |
137 | if (!IS_ERR_OR_NULL(mtd)) | |
138 | board_get_alt_info_mtd(mtd, buf); | |
139 | ||
140 | mtd = get_mtd_device_nm("spi-nand0"); | |
141 | if (!IS_ERR_OR_NULL(mtd)) | |
142 | board_get_alt_info_mtd(mtd, buf); | |
143 | } | |
ec2933e5 | 144 | |
75f9b190 PD |
145 | if (IS_ENABLED(CONFIG_DFU_VIRT)) { |
146 | strncat(buf, "&virt 0=OTP", DFU_ALT_BUF_LEN); | |
ec2933e5 | 147 | |
75f9b190 PD |
148 | if (IS_ENABLED(CONFIG_PMIC_STPMIC1)) |
149 | strncat(buf, "&virt 1=PMIC", DFU_ALT_BUF_LEN); | |
150 | } | |
ec2933e5 PD |
151 | |
152 | env_set("dfu_alt_info", buf); | |
153 | puts("DFU alt info setting: done\n"); | |
154 | } | |
155 | ||
156 | #if CONFIG_IS_ENABLED(DFU_VIRT) | |
157 | #include <dfu.h> | |
158 | #include <power/stpmic1.h> | |
159 | ||
160 | static int dfu_otp_read(u64 offset, u8 *buffer, long *size) | |
161 | { | |
162 | struct udevice *dev; | |
163 | int ret; | |
164 | ||
165 | ret = uclass_get_device_by_driver(UCLASS_MISC, | |
65e25bea | 166 | DM_DRIVER_GET(stm32mp_bsec), |
ec2933e5 PD |
167 | &dev); |
168 | if (ret) | |
169 | return ret; | |
170 | ||
171 | ret = misc_read(dev, offset + STM32_BSEC_OTP_OFFSET, buffer, *size); | |
172 | if (ret >= 0) { | |
173 | *size = ret; | |
174 | ret = 0; | |
175 | } | |
176 | ||
177 | return 0; | |
178 | } | |
179 | ||
180 | static int dfu_pmic_read(u64 offset, u8 *buffer, long *size) | |
181 | { | |
182 | int ret; | |
183 | #ifdef CONFIG_PMIC_STPMIC1 | |
184 | struct udevice *dev; | |
185 | ||
186 | ret = uclass_get_device_by_driver(UCLASS_MISC, | |
65e25bea | 187 | DM_DRIVER_GET(stpmic1_nvm), |
ec2933e5 PD |
188 | &dev); |
189 | if (ret) | |
190 | return ret; | |
191 | ||
192 | ret = misc_read(dev, 0xF8 + offset, buffer, *size); | |
193 | if (ret >= 0) { | |
194 | *size = ret; | |
195 | ret = 0; | |
196 | } | |
197 | if (ret == -EACCES) { | |
198 | *size = 0; | |
199 | ret = 0; | |
200 | } | |
201 | #else | |
202 | pr_err("PMIC update not supported"); | |
203 | ret = -EOPNOTSUPP; | |
204 | #endif | |
205 | ||
206 | return ret; | |
207 | } | |
208 | ||
209 | int dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset, | |
210 | void *buf, long *len) | |
211 | { | |
212 | switch (dfu->data.virt.dev_num) { | |
213 | case 0x0: | |
214 | return dfu_otp_read(offset, buf, len); | |
215 | case 0x1: | |
216 | return dfu_pmic_read(offset, buf, len); | |
217 | } | |
954bd1a9 PD |
218 | |
219 | if (CONFIG_IS_ENABLED(CMD_STM32PROG) && | |
220 | dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM) | |
221 | return stm32prog_read_medium_virt(dfu, offset, buf, len); | |
222 | ||
ec2933e5 PD |
223 | *len = 0; |
224 | return 0; | |
225 | } | |
226 | ||
954bd1a9 PD |
227 | int dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset, |
228 | void *buf, long *len) | |
229 | { | |
230 | if (CONFIG_IS_ENABLED(CMD_STM32PROG) && | |
231 | dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM) | |
232 | return stm32prog_write_medium_virt(dfu, offset, buf, len); | |
233 | ||
234 | return -EOPNOTSUPP; | |
235 | } | |
236 | ||
ec2933e5 PD |
237 | int __weak dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size) |
238 | { | |
954bd1a9 PD |
239 | if (CONFIG_IS_ENABLED(CMD_STM32PROG) && |
240 | dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM) | |
241 | return stm32prog_get_medium_size_virt(dfu, size); | |
242 | ||
ec2933e5 PD |
243 | *size = SZ_1K; |
244 | ||
245 | return 0; | |
246 | } | |
247 | ||
248 | #endif |