// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2020, STMicroelectronics - All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include #include #define DFU_ALT_BUF_LEN SZ_1K static void board_get_alt_info_mmc(struct udevice *dev, char *buf) { struct disk_partition info; int p, len, devnum; bool first = true; const char *name; struct mmc *mmc; struct blk_desc *desc; mmc = mmc_get_mmc_dev(dev); if (!mmc) return; if (mmc_init(mmc)) return; desc = mmc_get_blk_desc(mmc); if (!desc) return; name = blk_get_uclass_name(desc->uclass_id); devnum = desc->devnum; len = strlen(buf); if (buf[0] != '\0') len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "&"); len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "%s %d=", name, devnum); if (IS_MMC(mmc) && mmc->capacity_boot) { len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "%s%d_boot1 raw 0x0 0x%llx mmcpart 1;", name, devnum, mmc->capacity_boot); len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "%s%d_boot2 raw 0x0 0x%llx mmcpart 2", name, devnum, mmc->capacity_boot); first = false; } for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { if (part_get_info(desc, p, &info)) continue; if (!first) len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, ";"); first = false; len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "%s%d_%s part %d %d", name, devnum, info.name, devnum, p); } } static void board_get_alt_info_mtd(struct mtd_info *mtd, char *buf) { struct mtd_info *part; bool first = true; const char *name; int len, partnum = 0; name = mtd->name; len = strlen(buf); if (buf[0] != '\0') len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "&"); len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "mtd %s=", name); len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "%s raw 0x0 0x%llx ", name, mtd->size); list_for_each_entry(part, &mtd->partitions, node) { partnum++; if (!first) len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, ";"); first = false; len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "%s_%s part %d", name, part->name, partnum); } } void set_dfu_alt_info(char *interface, char *devstr) { struct udevice *dev; struct mtd_info *mtd; ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); if (env_get("dfu_alt_info")) return; memset(buf, 0, sizeof(buf)); snprintf(buf, DFU_ALT_BUF_LEN, "ram 0=%s", CONFIG_DFU_ALT_RAM0); if (CONFIG_IS_ENABLED(MMC)) { if (!uclass_get_device(UCLASS_MMC, 0, &dev)) board_get_alt_info_mmc(dev, buf); if (!uclass_get_device(UCLASS_MMC, 1, &dev)) board_get_alt_info_mmc(dev, buf); } if (CONFIG_IS_ENABLED(MTD)) { /* probe all MTD devices */ mtd_probe_devices(); /* probe SPI flash device on a bus */ if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev)) { mtd = get_mtd_device_nm("nor0"); if (!IS_ERR_OR_NULL(mtd)) board_get_alt_info_mtd(mtd, buf); mtd = get_mtd_device_nm("nor1"); if (!IS_ERR_OR_NULL(mtd)) board_get_alt_info_mtd(mtd, buf); } mtd = get_mtd_device_nm("nand0"); if (!IS_ERR_OR_NULL(mtd)) board_get_alt_info_mtd(mtd, buf); mtd = get_mtd_device_nm("spi-nand0"); if (!IS_ERR_OR_NULL(mtd)) board_get_alt_info_mtd(mtd, buf); } if (IS_ENABLED(CONFIG_DFU_VIRT) && IS_ENABLED(CMD_STM32PROG_USB)) { strncat(buf, "&virt 0=OTP", DFU_ALT_BUF_LEN); if (IS_ENABLED(CONFIG_PMIC_STPMIC1)) strncat(buf, "&virt 1=PMIC", DFU_ALT_BUF_LEN); } env_set("dfu_alt_info", buf); puts("DFU alt info setting: done\n"); } #if CONFIG_IS_ENABLED(DFU_VIRT) #include #include static int dfu_otp_read(u64 offset, u8 *buffer, long *size) { struct udevice *dev; int ret; ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(stm32mp_bsec), &dev); if (ret) return ret; ret = misc_read(dev, offset + STM32_BSEC_OTP_OFFSET, buffer, *size); if (ret >= 0) { *size = ret; ret = 0; } return 0; } static int dfu_pmic_read(u64 offset, u8 *buffer, long *size) { int ret; #ifdef CONFIG_PMIC_STPMIC1 struct udevice *dev; ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(stpmic1_nvm), &dev); if (ret) return ret; ret = misc_read(dev, 0xF8 + offset, buffer, *size); if (ret >= 0) { *size = ret; ret = 0; } if (ret == -EACCES) { *size = 0; ret = 0; } #else log_err("PMIC update not supported"); ret = -EOPNOTSUPP; #endif return ret; } int dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset, void *buf, long *len) { switch (dfu->data.virt.dev_num) { case 0x0: return dfu_otp_read(offset, buf, len); case 0x1: return dfu_pmic_read(offset, buf, len); } if (IS_ENABLED(CONFIG_CMD_STM32PROG_USB) && dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM) return stm32prog_read_medium_virt(dfu, offset, buf, len); *len = 0; return 0; } int dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset, void *buf, long *len) { if (IS_ENABLED(CONFIG_CMD_STM32PROG_USB) && dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM) return stm32prog_write_medium_virt(dfu, offset, buf, len); return -EOPNOTSUPP; } int __weak dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size) { if (IS_ENABLED(CONFIG_CMD_STM32PROG_USB) && dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM) return stm32prog_get_medium_size_virt(dfu, size); *size = SZ_1K; return 0; } #endif