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 33 enum { 34 PH = 0, /* P: Priority, H: high, M: middle, L: low*/ 35 PM, 36 PL, 37 }; 38 39 int rockchip_get_boot_mode(void) 40 { 41 struct bootloader_message *bmsg = NULL; 42 struct blk_desc *dev_desc; 43 disk_partition_t part_info; 44 uint32_t reg_boot_mode; 45 char *env_reboot_mode; 46 static int boot_mode[] = /* static */ 47 { -EINVAL, -EINVAL, -EINVAL }; 48 static int bcb_offset = -EINVAL; /* static */ 49 int clear_boot_reg = 0; 50 int ret, cnt; 51 #ifdef CONFIG_ANDROID_BOOT_IMAGE 52 u32 offset = android_bcb_msg_sector_offset(); 53 #else 54 u32 offset = BCB_MESSAGE_BLK_OFFSET; 55 #endif 56 57 /* 58 * Here, we mainly check for: 59 * In rockusb_download(), that recovery key is pressed without 60 * USB attach will do env_set("reboot_mode", "recovery"); 61 */ 62 env_reboot_mode = env_get("reboot_mode"); 63 if (env_reboot_mode) { 64 if (!strcmp(env_reboot_mode, "recovery-key")) { 65 printf("boot mode: recovery (key)\n"); 66 return BOOT_MODE_RECOVERY; 67 } else if (!strcmp(env_reboot_mode, "recovery-usb")) { 68 printf("boot mode: recovery (usb)\n"); 69 return BOOT_MODE_RECOVERY; 70 } else if (!strcmp(env_reboot_mode, "recovery")) { 71 printf("boot mode: recovery (env)\n"); 72 return BOOT_MODE_RECOVERY; 73 } else if (!strcmp(env_reboot_mode, "fastboot")) { 74 printf("boot mode: fastboot\n"); 75 return BOOT_MODE_BOOTLOADER; 76 } 77 } 78 79 /* 80 * Special handle: 81 * Once the BCB offset changes, reinitalize "boot_mode". 82 * 83 * Background: 84 * 1. there are two Android BCB at the 0x00 and 0x20 offset in 85 * misc.img to compatible legacy(0x20) SDK. 86 * 2. android_bcb_msg_sector_offset() is for android image: 87 * return 0x20 if image version < 10, otherwise 0x00. 88 * 3. If not android image, BCB at 0x20 is the valid one. 89 * 90 * U-Boot can support booting both FIT & Android image, if FIT 91 * boot flow enters here early than Android, the "boot_mode" is 92 * set as BOOT_MODE_RECOVERY according to BCB at 0x20 offset. 93 * After that, this function always return static variable "boot_mode" 94 * as BOOT_MODE_RECOVERY even android(>=10) boot flow enter here. 95 * 96 * PH and PL is from boot mode register, reading once. 97 * PM is from misc.img and should be updated if BCB offset is changed. 98 * Return the boot mode according to priority: PH > PM > PL. 99 */ 100 if (bcb_offset != offset) { 101 boot_mode[PM] = -EINVAL; 102 bcb_offset = offset; 103 } 104 105 /* directly return if there is already valid mode */ 106 if (boot_mode[PH] != -EINVAL) 107 return boot_mode[PH]; 108 else if (boot_mode[PM] != -EINVAL) 109 return boot_mode[PM]; 110 else if (boot_mode[PL] != -EINVAL) 111 return boot_mode[PL]; 112 113 dev_desc = rockchip_get_bootdev(); 114 if (!dev_desc) { 115 printf("dev_desc is NULL!\n"); 116 return -ENODEV; 117 } 118 119 ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info); 120 if (ret < 0) { 121 printf("No misc partition\n"); 122 goto fallback; 123 } 124 125 cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), dev_desc->blksz); 126 bmsg = memalign(ARCH_DMA_MINALIGN, cnt * dev_desc->blksz); 127 ret = blk_dread(dev_desc, part_info.start + bcb_offset, cnt, bmsg); 128 if (ret != cnt) { 129 free(bmsg); 130 return -EIO; 131 } 132 133 fallback: 134 /* 135 * Boot mode priority 136 * 137 * Anyway, we should set download boot mode as the highest priority, so: 138 * 139 * reboot loader/bootloader/fastboot > misc partition "recovery" > reboot xxx. 140 */ 141 reg_boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG); 142 if (reg_boot_mode == BOOT_LOADER) { 143 printf("boot mode: loader\n"); 144 boot_mode[PH] = BOOT_MODE_LOADER; 145 clear_boot_reg = 1; 146 } else if (reg_boot_mode == BOOT_FASTBOOT) { 147 printf("boot mode: bootloader\n"); 148 boot_mode[PH] = BOOT_MODE_BOOTLOADER; 149 clear_boot_reg = 1; 150 } else if (bmsg && !strcmp(bmsg->command, "boot-recovery")) { 151 printf("boot mode: recovery (misc)\n"); 152 boot_mode[PM] = BOOT_MODE_RECOVERY; 153 } else { 154 switch (reg_boot_mode) { 155 case BOOT_NORMAL: 156 printf("boot mode: normal\n"); 157 boot_mode[PL] = BOOT_MODE_NORMAL; 158 clear_boot_reg = 1; 159 break; 160 case BOOT_RECOVERY: 161 printf("boot mode: recovery (cmd)\n"); 162 boot_mode[PL] = BOOT_MODE_RECOVERY; 163 clear_boot_reg = 1; 164 break; 165 case BOOT_UMS: 166 printf("boot mode: ums\n"); 167 boot_mode[PL] = BOOT_MODE_UMS; 168 clear_boot_reg = 1; 169 break; 170 case BOOT_CHARGING: 171 printf("boot mode: charging\n"); 172 boot_mode[PL] = BOOT_MODE_CHARGING; 173 clear_boot_reg = 1; 174 break; 175 case BOOT_PANIC: 176 printf("boot mode: panic\n"); 177 boot_mode[PL] = BOOT_MODE_PANIC; 178 break; 179 case BOOT_WATCHDOG: 180 printf("boot mode: watchdog\n"); 181 boot_mode[PL] = BOOT_MODE_WATCHDOG; 182 break; 183 default: 184 printf("boot mode: None\n"); 185 boot_mode[PL] = BOOT_MODE_UNDEFINE; 186 } 187 } 188 189 /* 190 * We don't clear boot mode reg when its value stands for the reboot 191 * reason or others(in the future), the kernel will need and clear it. 192 */ 193 if (clear_boot_reg) 194 writel(BOOT_NORMAL, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG); 195 196 if (boot_mode[PH] != -EINVAL) 197 return boot_mode[PH]; 198 else if (boot_mode[PM] != -EINVAL) 199 return boot_mode[PM]; 200 else 201 return boot_mode[PL]; 202 } 203 204 int setup_boot_mode(void) 205 { 206 char env_preboot[256] = {0}; 207 208 switch (rockchip_get_boot_mode()) { 209 case BOOT_MODE_BOOTLOADER: 210 printf("enter fastboot!\n"); 211 #if defined(CONFIG_FASTBOOT_FLASH_MMC_DEV) 212 snprintf(env_preboot, 256, 213 "setenv preboot; mmc dev %x; fastboot usb 0; ", 214 CONFIG_FASTBOOT_FLASH_MMC_DEV); 215 #elif defined(CONFIG_FASTBOOT_FLASH_NAND_DEV) 216 snprintf(env_preboot, 256, 217 "setenv preboot; fastboot usb 0; "); 218 #endif 219 env_set("preboot", env_preboot); 220 break; 221 case BOOT_MODE_UMS: 222 printf("enter UMS!\n"); 223 env_set("preboot", "setenv preboot; ums mmc 0"); 224 break; 225 case BOOT_MODE_LOADER: 226 printf("enter Rockusb!\n"); 227 env_set("preboot", "setenv preboot; rockusb 0 ${devtype} ${devnum}; rbrom"); 228 break; 229 case BOOT_MODE_CHARGING: 230 printf("enter charging!\n"); 231 env_set("preboot", "setenv preboot; charge"); 232 break; 233 } 234 235 return 0; 236 } 237