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 * 17*df7cce43SAlex Deymo * @dev_iface: Device interface. 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 char *ep; 2906f4a874SAlex Deymo const char *part_str; 3006f4a874SAlex Deymo int dev_num; 3106f4a874SAlex Deymo 3206f4a874SAlex Deymo part_str = strchr(dev_part_str, ';'); 3306f4a874SAlex Deymo if (!part_str) 3406f4a874SAlex Deymo return -1; 3506f4a874SAlex Deymo 3606f4a874SAlex Deymo dev_num = simple_strtoul(dev_part_str, &ep, 16); 3706f4a874SAlex Deymo if (ep != part_str) { 3806f4a874SAlex Deymo /* Not all the first part before the ; was parsed. */ 3906f4a874SAlex Deymo return -1; 4006f4a874SAlex Deymo } 4106f4a874SAlex Deymo part_str++; 4206f4a874SAlex Deymo 43*df7cce43SAlex Deymo *dev_desc = blk_get_dev(dev_iface, dev_num); 4406f4a874SAlex Deymo if (!*dev_desc) { 45*df7cce43SAlex Deymo printf("Could not find %s %d\n", dev_iface, dev_num); 4606f4a874SAlex Deymo return -1; 4706f4a874SAlex Deymo } 4806f4a874SAlex Deymo if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) { 4906f4a874SAlex Deymo printf("Could not find \"%s\" partition\n", part_str); 5006f4a874SAlex Deymo return -1; 5106f4a874SAlex Deymo } 5206f4a874SAlex Deymo return 0; 5306f4a874SAlex Deymo } 5406f4a874SAlex Deymo 5506f4a874SAlex Deymo static int do_boot_android(cmd_tbl_t *cmdtp, int flag, int argc, 5606f4a874SAlex Deymo char * const argv[]) 5706f4a874SAlex Deymo { 5806f4a874SAlex Deymo unsigned long load_address; 5906f4a874SAlex Deymo int ret = CMD_RET_SUCCESS; 6006f4a874SAlex Deymo char *addr_arg_endp, *addr_str; 6106f4a874SAlex Deymo struct blk_desc *dev_desc; 6206f4a874SAlex Deymo disk_partition_t part_info; 6306f4a874SAlex Deymo const char *misc_part_iface; 6406f4a874SAlex Deymo const char *misc_part_desc; 6506f4a874SAlex Deymo 6680622240SAlex Deymo if (argc < 4) 6706f4a874SAlex Deymo return CMD_RET_USAGE; 6880622240SAlex Deymo if (argc > 5) 6906f4a874SAlex Deymo return CMD_RET_USAGE; 7006f4a874SAlex Deymo 7180622240SAlex Deymo if (argc >= 5) { 7280622240SAlex Deymo load_address = simple_strtoul(argv[4], &addr_arg_endp, 16); 7380622240SAlex Deymo if (addr_arg_endp == argv[4] || *addr_arg_endp != '\0') 7406f4a874SAlex Deymo return CMD_RET_USAGE; 7506f4a874SAlex Deymo } else { 7606f4a874SAlex Deymo addr_str = env_get("loadaddr"); 7706f4a874SAlex Deymo if (addr_str) 7806f4a874SAlex Deymo load_address = simple_strtoul(addr_str, NULL, 16); 7906f4a874SAlex Deymo else 8006f4a874SAlex Deymo load_address = CONFIG_SYS_LOAD_ADDR; 8106f4a874SAlex Deymo } 8206f4a874SAlex Deymo 8306f4a874SAlex Deymo /* Lookup the "misc" partition from argv[1] and argv[2] */ 8406f4a874SAlex Deymo misc_part_iface = argv[1]; 8506f4a874SAlex Deymo misc_part_desc = argv[2]; 8606f4a874SAlex Deymo /* Split the part_name if passed as "$dev_num;part_name". */ 8706f4a874SAlex Deymo if (part_get_info_by_dev_and_name(misc_part_iface, misc_part_desc, 8806f4a874SAlex Deymo &dev_desc, &part_info) < 0) { 8906f4a874SAlex Deymo /* Couldn't lookup by name from mmc, try looking up the 9006f4a874SAlex Deymo * partition description directly. 9106f4a874SAlex Deymo */ 9206f4a874SAlex Deymo if (blk_get_device_part_str(misc_part_iface, misc_part_desc, 9306f4a874SAlex Deymo &dev_desc, &part_info, 1) < 0) { 9406f4a874SAlex Deymo printf("Couldn't find partition %s %s\n", 9506f4a874SAlex Deymo misc_part_iface, misc_part_desc); 9606f4a874SAlex Deymo return CMD_RET_FAILURE; 9706f4a874SAlex Deymo } 9806f4a874SAlex Deymo } 9906f4a874SAlex Deymo 10080622240SAlex Deymo ret = android_bootloader_boot_flow(dev_desc, &part_info, argv[3], 10180622240SAlex Deymo load_address); 10206f4a874SAlex Deymo if (ret < 0) { 10306f4a874SAlex Deymo printf("Android boot failed, error %d.\n", ret); 10406f4a874SAlex Deymo return CMD_RET_FAILURE; 10506f4a874SAlex Deymo } 10606f4a874SAlex Deymo return CMD_RET_SUCCESS; 10706f4a874SAlex Deymo } 10806f4a874SAlex Deymo 10906f4a874SAlex Deymo U_BOOT_CMD( 11080622240SAlex Deymo boot_android, 5, 0, do_boot_android, 11106f4a874SAlex Deymo "Execute the Android Bootloader flow.", 112*df7cce43SAlex Deymo "<interface> <dev[:part|;part_name]> <slot> [<kernel_addr>]\n" 11306f4a874SAlex Deymo " - Load the Boot Control Block (BCB) from the partition 'part' on\n" 11406f4a874SAlex Deymo " device type 'interface' instance 'dev' to determine the boot\n" 11506f4a874SAlex Deymo " mode, and load and execute the appropriate kernel.\n" 11606f4a874SAlex Deymo " In normal and recovery mode, the kernel will be loaded from\n" 11706f4a874SAlex Deymo " the corresponding \"boot\" partition. In bootloader mode, the\n" 11806f4a874SAlex Deymo " command defined in the \"fastbootcmd\" variable will be\n" 11906f4a874SAlex Deymo " executed.\n" 12080622240SAlex Deymo " On Android devices with multiple slots, the pass 'slot' is\n" 12180622240SAlex Deymo " used to load the appropriate kernel. The standard slot names\n" 12280622240SAlex Deymo " are 'a' and 'b'.\n" 12306f4a874SAlex Deymo " - If 'part_name' is passed, preceded with a ; instead of :, the\n" 12406f4a874SAlex Deymo " partition name whose label is 'part_name' will be looked up in\n" 12506f4a874SAlex Deymo " the partition table. This is commonly the \"misc\" partition.\n" 12606f4a874SAlex Deymo ); 127