1 /* 2 * (C) Copyright 2016 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <boot_rkimg.h> 9 #include <malloc.h> 10 #include <asm/io.h> 11 #include <asm/arch/boot_mode.h> 12 13 DECLARE_GLOBAL_DATA_PTR; 14 15 /* 16 * Generally, we have 3 ways to get reboot mode: 17 * 18 * 1. from bootloader_message which is defined in MISC partition; 19 * 2. from CONFIG_ROCKCHIP_BOOT_MODE_REG which supports "reboot xxx" commands; 20 * 3. from env "reboot_mode" which is added by U-Boot code(currently only when 21 * recovery key pressed); 22 * 23 * 1st and 2nd cases are static determined at system start and we check it once, 24 * while 3th case is dynamically added by U-Boot code, so we have to check it 25 * everytime. 26 * 27 * Recovery mode from: 28 * - MISC partition; 29 * - "reboot recovery" command; 30 * - recovery key pressed without usb attach; 31 */ 32 int rockchip_get_boot_mode(void) 33 { 34 struct bootloader_message *bmsg = NULL; 35 struct blk_desc *dev_desc; 36 disk_partition_t part_info; 37 uint32_t reg_boot_mode; 38 char *env_reboot_mode; 39 static int boot_mode = -1; /* static */ 40 int clear_boot_reg = 0; 41 int ret, cnt; 42 #ifdef CONFIG_ANDROID_BOOT_IMAGE 43 u32 bcb_offset = android_bcb_msg_sector_offset(); 44 #else 45 u32 bcb_offset = BCB_MESSAGE_BLK_OFFSET; 46 #endif 47 48 /* 49 * Here, we mainly check for: 50 * In rockusb_download(), that recovery key is pressed without 51 * USB attach will do env_set("reboot_mode", "recovery"); 52 */ 53 env_reboot_mode = env_get("reboot_mode"); 54 if (env_reboot_mode) { 55 if (!strcmp(env_reboot_mode, "recovery-key")) { 56 boot_mode = BOOT_MODE_RECOVERY; 57 printf("boot mode: recovery (key)\n"); 58 } else if (!strcmp(env_reboot_mode, "recovery-usb")) { 59 boot_mode = BOOT_MODE_RECOVERY; 60 printf("boot mode: recovery (usb)\n"); 61 } else if (!strcmp(env_reboot_mode, "recovery")) { 62 boot_mode = BOOT_MODE_RECOVERY; 63 printf("boot mode: recovery(env)\n"); 64 } else if (!strcmp(env_reboot_mode, "fastboot")) { 65 boot_mode = BOOT_MODE_BOOTLOADER; 66 printf("boot mode: fastboot\n"); 67 } 68 } 69 70 if (boot_mode != -1) 71 return boot_mode; 72 73 dev_desc = rockchip_get_bootdev(); 74 if (!dev_desc) { 75 printf("dev_desc is NULL!\n"); 76 return -ENODEV; 77 } 78 79 ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info); 80 if (ret < 0) { 81 printf("No misc partition\n"); 82 goto fallback; 83 } 84 85 cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), dev_desc->blksz); 86 bmsg = memalign(ARCH_DMA_MINALIGN, cnt * dev_desc->blksz); 87 ret = blk_dread(dev_desc, 88 part_info.start + bcb_offset, 89 cnt, bmsg); 90 if (ret != cnt) { 91 free(bmsg); 92 return -EIO; 93 } 94 95 fallback: 96 /* 97 * Boot mode priority 98 * 99 * Anyway, we should set download boot mode as the highest priority, so: 100 * 101 * reboot loader/bootloader/fastboot > misc partition "recovery" > reboot xxx. 102 */ 103 reg_boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG); 104 if (reg_boot_mode == BOOT_LOADER) { 105 printf("boot mode: loader\n"); 106 boot_mode = BOOT_MODE_LOADER; 107 clear_boot_reg = 1; 108 } else if (reg_boot_mode == BOOT_FASTBOOT) { 109 printf("boot mode: bootloader\n"); 110 boot_mode = BOOT_MODE_BOOTLOADER; 111 clear_boot_reg = 1; 112 } else if (bmsg && !strcmp(bmsg->command, "boot-recovery")) { 113 printf("boot mode: recovery (misc)\n"); 114 boot_mode = BOOT_MODE_RECOVERY; 115 clear_boot_reg = 1; 116 } else { 117 switch (reg_boot_mode) { 118 case BOOT_NORMAL: 119 printf("boot mode: normal\n"); 120 boot_mode = BOOT_MODE_NORMAL; 121 clear_boot_reg = 1; 122 break; 123 case BOOT_RECOVERY: 124 printf("boot mode: recovery (cmd)\n"); 125 boot_mode = BOOT_MODE_RECOVERY; 126 clear_boot_reg = 1; 127 break; 128 case BOOT_UMS: 129 printf("boot mode: ums\n"); 130 boot_mode = BOOT_MODE_UMS; 131 clear_boot_reg = 1; 132 break; 133 case BOOT_CHARGING: 134 printf("boot mode: charging\n"); 135 boot_mode = BOOT_MODE_CHARGING; 136 clear_boot_reg = 1; 137 break; 138 case BOOT_PANIC: 139 printf("boot mode: panic\n"); 140 boot_mode = BOOT_MODE_PANIC; 141 break; 142 case BOOT_WATCHDOG: 143 printf("boot mode: watchdog\n"); 144 boot_mode = BOOT_MODE_WATCHDOG; 145 break; 146 default: 147 printf("boot mode: None\n"); 148 boot_mode = BOOT_MODE_UNDEFINE; 149 } 150 } 151 152 /* 153 * We don't clear boot mode reg when its value stands for the reboot 154 * reason or others(in the future), the kernel will need and clear it. 155 */ 156 if (clear_boot_reg) 157 writel(BOOT_NORMAL, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG); 158 159 return boot_mode; 160 } 161 162 int setup_boot_mode(void) 163 { 164 char env_preboot[256] = {0}; 165 166 switch (rockchip_get_boot_mode()) { 167 case BOOT_MODE_BOOTLOADER: 168 printf("enter fastboot!\n"); 169 #if defined(CONFIG_FASTBOOT_FLASH_MMC_DEV) 170 snprintf(env_preboot, 256, 171 "setenv preboot; mmc dev %x; fastboot usb 0; ", 172 CONFIG_FASTBOOT_FLASH_MMC_DEV); 173 #elif defined(CONFIG_FASTBOOT_FLASH_NAND_DEV) 174 snprintf(env_preboot, 256, 175 "setenv preboot; fastboot usb 0; "); 176 #endif 177 env_set("preboot", env_preboot); 178 break; 179 case BOOT_MODE_UMS: 180 printf("enter UMS!\n"); 181 env_set("preboot", "setenv preboot; ums mmc 0"); 182 break; 183 case BOOT_MODE_LOADER: 184 printf("enter Rockusb!\n"); 185 env_set("preboot", "setenv preboot; rockusb 0 ${devtype} ${devnum}; rbrom"); 186 break; 187 case BOOT_MODE_CHARGING: 188 printf("enter charging!\n"); 189 env_set("preboot", "setenv preboot; charge"); 190 break; 191 } 192 193 return 0; 194 } 195