106f4a874SAlex Deymo /* 206f4a874SAlex Deymo * Copyright (C) 2016 The Android Open Source Project 306f4a874SAlex Deymo * 406f4a874SAlex Deymo * SPDX-License-Identifier: BSD-2-Clause 506f4a874SAlex Deymo */ 606f4a874SAlex Deymo 706f4a874SAlex Deymo #include <android_bootloader.h> 806f4a874SAlex Deymo #include <common.h> 906f4a874SAlex Deymo #include <command.h> 1006f4a874SAlex Deymo 1106f4a874SAlex Deymo /** 1206f4a874SAlex Deymo * part_get_info_by_dev_and_name - Parse a device number and partition name 1306f4a874SAlex Deymo * string in the form of "device_num;partition_name", for example "0;misc". 1406f4a874SAlex Deymo * If the partition is found, sets dev_desc and part_info accordingly with the 1506f4a874SAlex Deymo * information of the partition with the given partition_name. 1606f4a874SAlex Deymo * 1706f4a874SAlex Deymo * @dev_iface: Device interface. Only "mmc" is supported at the moment. 1806f4a874SAlex Deymo * @dev_part_str: Input string argument, like "0;misc". 1906f4a874SAlex Deymo * @dev_desc: Place to put the device description pointer. 2006f4a874SAlex Deymo * @part_info: Place to put the partition information. 2106f4a874SAlex Deymo * @return 0 on success, or -1 on error 2206f4a874SAlex Deymo */ 2306f4a874SAlex Deymo static int part_get_info_by_dev_and_name(const char *dev_iface, 2406f4a874SAlex Deymo const char *dev_part_str, 2506f4a874SAlex Deymo struct blk_desc **dev_desc, 2606f4a874SAlex Deymo disk_partition_t *part_info) 2706f4a874SAlex Deymo { 2806f4a874SAlex Deymo #ifdef CONFIG_EFI_PARTITION 2906f4a874SAlex Deymo char *ep; 3006f4a874SAlex Deymo const char *part_str; 3106f4a874SAlex Deymo int dev_num; 3206f4a874SAlex Deymo 3306f4a874SAlex Deymo /* We only support "mmc" for looking up partition names. */ 3406f4a874SAlex Deymo if (strcmp(dev_iface, "mmc") != 0) 3506f4a874SAlex Deymo return -1; 3606f4a874SAlex Deymo 3706f4a874SAlex Deymo part_str = strchr(dev_part_str, ';'); 3806f4a874SAlex Deymo if (!part_str) 3906f4a874SAlex Deymo return -1; 4006f4a874SAlex Deymo 4106f4a874SAlex Deymo dev_num = simple_strtoul(dev_part_str, &ep, 16); 4206f4a874SAlex Deymo if (ep != part_str) { 4306f4a874SAlex Deymo /* Not all the first part before the ; was parsed. */ 4406f4a874SAlex Deymo return -1; 4506f4a874SAlex Deymo } 4606f4a874SAlex Deymo part_str++; 4706f4a874SAlex Deymo 4806f4a874SAlex Deymo *dev_desc = blk_get_dev("mmc", dev_num); 4906f4a874SAlex Deymo if (!*dev_desc) { 5006f4a874SAlex Deymo printf("Could not find mmc %d\n", dev_num); 5106f4a874SAlex Deymo return -1; 5206f4a874SAlex Deymo } 5306f4a874SAlex Deymo if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) { 5406f4a874SAlex Deymo printf("Could not find \"%s\" partition\n", part_str); 5506f4a874SAlex Deymo return -1; 5606f4a874SAlex Deymo } 5706f4a874SAlex Deymo return 0; 5806f4a874SAlex Deymo #else 5906f4a874SAlex Deymo return -1; 6006f4a874SAlex Deymo #endif /* CONFIG_EFI_PARTITION */ 6106f4a874SAlex Deymo } 6206f4a874SAlex Deymo 6306f4a874SAlex Deymo static int do_boot_android(cmd_tbl_t *cmdtp, int flag, int argc, 6406f4a874SAlex Deymo char * const argv[]) 6506f4a874SAlex Deymo { 6606f4a874SAlex Deymo unsigned long load_address; 6706f4a874SAlex Deymo int ret = CMD_RET_SUCCESS; 6806f4a874SAlex Deymo char *addr_arg_endp, *addr_str; 6906f4a874SAlex Deymo struct blk_desc *dev_desc; 7006f4a874SAlex Deymo disk_partition_t part_info; 7106f4a874SAlex Deymo const char *misc_part_iface; 7206f4a874SAlex Deymo const char *misc_part_desc; 7306f4a874SAlex Deymo 74*80622240SAlex Deymo if (argc < 4) 7506f4a874SAlex Deymo return CMD_RET_USAGE; 76*80622240SAlex Deymo if (argc > 5) 7706f4a874SAlex Deymo return CMD_RET_USAGE; 7806f4a874SAlex Deymo 79*80622240SAlex Deymo if (argc >= 5) { 80*80622240SAlex Deymo load_address = simple_strtoul(argv[4], &addr_arg_endp, 16); 81*80622240SAlex Deymo if (addr_arg_endp == argv[4] || *addr_arg_endp != '\0') 8206f4a874SAlex Deymo return CMD_RET_USAGE; 8306f4a874SAlex Deymo } else { 8406f4a874SAlex Deymo addr_str = env_get("loadaddr"); 8506f4a874SAlex Deymo if (addr_str) 8606f4a874SAlex Deymo load_address = simple_strtoul(addr_str, NULL, 16); 8706f4a874SAlex Deymo else 8806f4a874SAlex Deymo load_address = CONFIG_SYS_LOAD_ADDR; 8906f4a874SAlex Deymo } 9006f4a874SAlex Deymo 9106f4a874SAlex Deymo /* Lookup the "misc" partition from argv[1] and argv[2] */ 9206f4a874SAlex Deymo misc_part_iface = argv[1]; 9306f4a874SAlex Deymo misc_part_desc = argv[2]; 9406f4a874SAlex Deymo /* Split the part_name if passed as "$dev_num;part_name". */ 9506f4a874SAlex Deymo if (part_get_info_by_dev_and_name(misc_part_iface, misc_part_desc, 9606f4a874SAlex Deymo &dev_desc, &part_info) < 0) { 9706f4a874SAlex Deymo /* Couldn't lookup by name from mmc, try looking up the 9806f4a874SAlex Deymo * partition description directly. 9906f4a874SAlex Deymo */ 10006f4a874SAlex Deymo if (blk_get_device_part_str(misc_part_iface, misc_part_desc, 10106f4a874SAlex Deymo &dev_desc, &part_info, 1) < 0) { 10206f4a874SAlex Deymo printf("Couldn't find partition %s %s\n", 10306f4a874SAlex Deymo misc_part_iface, misc_part_desc); 10406f4a874SAlex Deymo return CMD_RET_FAILURE; 10506f4a874SAlex Deymo } 10606f4a874SAlex Deymo } 10706f4a874SAlex Deymo 108*80622240SAlex Deymo ret = android_bootloader_boot_flow(dev_desc, &part_info, argv[3], 109*80622240SAlex Deymo load_address); 11006f4a874SAlex Deymo if (ret < 0) { 11106f4a874SAlex Deymo printf("Android boot failed, error %d.\n", ret); 11206f4a874SAlex Deymo return CMD_RET_FAILURE; 11306f4a874SAlex Deymo } 11406f4a874SAlex Deymo return CMD_RET_SUCCESS; 11506f4a874SAlex Deymo } 11606f4a874SAlex Deymo 11706f4a874SAlex Deymo U_BOOT_CMD( 118*80622240SAlex Deymo boot_android, 5, 0, do_boot_android, 11906f4a874SAlex Deymo "Execute the Android Bootloader flow.", 12006f4a874SAlex Deymo "<interface> <dev[:part" 12106f4a874SAlex Deymo #if defined(CONFIG_EFI_PARTITION) 12206f4a874SAlex Deymo /* When EFI is enabled we also support looking up a partition name. */ 12306f4a874SAlex Deymo "|;part_name" 12406f4a874SAlex Deymo #endif /* CONFIG_EFI_PARTITION */ 125*80622240SAlex Deymo "]> <slot> [<kernel_addr>]\n" 12606f4a874SAlex Deymo " - Load the Boot Control Block (BCB) from the partition 'part' on\n" 12706f4a874SAlex Deymo " device type 'interface' instance 'dev' to determine the boot\n" 12806f4a874SAlex Deymo " mode, and load and execute the appropriate kernel.\n" 12906f4a874SAlex Deymo " In normal and recovery mode, the kernel will be loaded from\n" 13006f4a874SAlex Deymo " the corresponding \"boot\" partition. In bootloader mode, the\n" 13106f4a874SAlex Deymo " command defined in the \"fastbootcmd\" variable will be\n" 13206f4a874SAlex Deymo " executed.\n" 133*80622240SAlex Deymo " On Android devices with multiple slots, the pass 'slot' is\n" 134*80622240SAlex Deymo " used to load the appropriate kernel. The standard slot names\n" 135*80622240SAlex Deymo " are 'a' and 'b'.\n" 13606f4a874SAlex Deymo #if defined(CONFIG_EFI_PARTITION) 13706f4a874SAlex Deymo " - If 'part_name' is passed, preceded with a ; instead of :, the\n" 13806f4a874SAlex Deymo " partition name whose label is 'part_name' will be looked up in\n" 13906f4a874SAlex Deymo " the partition table. This is commonly the \"misc\" partition.\n" 14006f4a874SAlex Deymo #endif /* CONFIG_EFI_PARTITION */ 14106f4a874SAlex Deymo ); 142