1 /* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <adc.h> 9 #include <bidram.h> 10 #include <bootm.h> 11 #include <boot_rkimg.h> 12 #include <cli.h> 13 #include <dm.h> 14 #include <image.h> 15 #include <key.h> 16 #include <mmc.h> 17 #include <malloc.h> 18 #include <stdlib.h> 19 #include <sysmem.h> 20 #include <asm/io.h> 21 #include <asm/arch/boot_mode.h> 22 #include <asm/arch/hotkey.h> 23 #include <asm/arch/param.h> 24 #include <asm/arch/resource_img.h> 25 #include <linux/usb/phy-rockchip-inno-usb2.h> 26 27 DECLARE_GLOBAL_DATA_PTR; 28 29 static void boot_devtype_init(void) 30 { 31 const char *devtype_num_set = "run rkimg_bootdev"; 32 char *devtype = NULL, *devnum = NULL; 33 static int done; /* static */ 34 int atags_en = 0; 35 int ret; 36 37 if (done) 38 return; 39 40 ret = param_parse_bootdev(&devtype, &devnum); 41 if (!ret) { 42 atags_en = 1; 43 env_set("devtype", devtype); 44 env_set("devnum", devnum); 45 46 #ifdef CONFIG_DM_MMC 47 if (!strcmp("mmc", devtype)) 48 mmc_initialize(gd->bd); 49 #endif 50 /* 51 * For example, the pre-loader do not have mtd device, 52 * and pass devtype is nand. Then U-Boot can not get 53 * dev_desc when use mtd driver to read firmware. So 54 * test the block dev is exist or not here. 55 * 56 * And the devtype & devnum maybe wrong sometimes, it 57 * is better to test first. 58 */ 59 if (blk_get_devnum_by_typename(devtype, atoi(devnum))) 60 goto finish; 61 } 62 63 /* If not find valid bootdev by atags, scan all possible */ 64 #ifdef CONFIG_DM_MMC 65 mmc_initialize(gd->bd); 66 #endif 67 ret = run_command_list(devtype_num_set, -1, 0); 68 if (ret) { 69 /* Set default dev type/num if command not valid */ 70 devtype = "mmc"; 71 devnum = "0"; 72 env_set("devtype", devtype); 73 env_set("devnum", devnum); 74 } 75 76 finish: 77 done = 1; 78 printf("Bootdev%s: %s %s\n", atags_en ? "(atags)" : "", 79 env_get("devtype"), env_get("devnum")); 80 } 81 82 static int get_bootdev_type(void) 83 { 84 char *boot_media = NULL, *devtype = NULL; 85 char boot_options[128] = {0}; 86 static int appended; 87 ulong devnum = 0; 88 int type = 0; 89 90 devtype = env_get("devtype"); 91 devnum = env_get_ulong("devnum", 10, 0); 92 93 /* For current use(Only EMMC support!) */ 94 if (!devtype) { 95 devtype = "mmc"; 96 printf("Use emmc as default boot media\n"); 97 } 98 99 if (!strcmp(devtype, "mmc")) { 100 type = IF_TYPE_MMC; 101 if (devnum == 1) 102 boot_media = "sd"; 103 else 104 boot_media = "emmc"; 105 } else if (!strcmp(devtype, "rknand")) { 106 type = IF_TYPE_RKNAND; 107 boot_media = "nand"; 108 } else if (!strcmp(devtype, "spinand")) { 109 type = IF_TYPE_SPINAND; 110 boot_media = "nand"; /* kernel treat sfc nand as nand device */ 111 } else if (!strcmp(devtype, "spinor")) { 112 type = IF_TYPE_SPINOR; 113 boot_media = "nor"; 114 } else if (!strcmp(devtype, "ramdisk")) { 115 type = IF_TYPE_RAMDISK; 116 boot_media = "ramdisk"; 117 } else if (!strcmp(devtype, "mtd")) { 118 type = IF_TYPE_MTD; 119 boot_media = "mtd"; 120 } else { 121 /* Add new to support */ 122 } 123 124 if (!appended && boot_media) { 125 appended = 1; 126 127 /* 128 * The legacy rockchip Android (SDK < 8.1) requires "androidboot.mode=" 129 * to be "charger" or boot media which is a rockchip private solution. 130 * 131 * The official Android rule (SDK >= 8.1) is: 132 * "androidboot.mode=normal" or "androidboot.mode=charger". 133 * 134 * Now that this U-Boot is usually working with higher version 135 * Android (SDK >= 8.1), we follow the official rules. 136 * 137 * Common: androidboot.mode=charger has higher priority, don't override; 138 */ 139 #ifdef CONFIG_RKIMG_ANDROID_BOOTMODE_LEGACY 140 /* rknand doesn't need "androidboot.mode="; */ 141 if (env_exist("bootargs", "androidboot.mode=charger") || 142 (type == IF_TYPE_RKNAND) || 143 (type == IF_TYPE_SPINAND) || 144 (type == IF_TYPE_SPINOR)) 145 snprintf(boot_options, sizeof(boot_options), 146 "storagemedia=%s", boot_media); 147 else 148 snprintf(boot_options, sizeof(boot_options), 149 "storagemedia=%s androidboot.mode=%s", 150 boot_media, boot_media); 151 #else 152 /* 153 * 1. "storagemedia": This is a legacy variable to indicate board 154 * storage media for kernel and android. 155 * 156 * 2. "androidboot.storagemedia": The same purpose as "storagemedia", 157 * but the android framework will auto create property by 158 * variable with format "androidboot.xxx", eg: 159 * 160 * "androidboot.storagemedia" => "ro.boot.storagemedia". 161 * 162 * So, U-Boot pass this new variable is only for the convenience 163 * to Android. 164 */ 165 if (env_exist("bootargs", "androidboot.mode=charger")) 166 snprintf(boot_options, sizeof(boot_options), 167 "storagemedia=%s androidboot.storagemedia=%s", 168 boot_media, boot_media); 169 else 170 snprintf(boot_options, sizeof(boot_options), 171 "storagemedia=%s androidboot.storagemedia=%s " 172 "androidboot.mode=normal ", 173 boot_media, boot_media); 174 #endif 175 env_update("bootargs", boot_options); 176 } 177 178 return type; 179 } 180 181 static struct blk_desc *dev_desc; 182 183 struct blk_desc *rockchip_get_bootdev(void) 184 { 185 int dev_type; 186 int devnum; 187 188 if (dev_desc) 189 return dev_desc; 190 191 boot_devtype_init(); 192 dev_type = get_bootdev_type(); 193 devnum = env_get_ulong("devnum", 10, 0); 194 195 dev_desc = blk_get_devnum_by_type(dev_type, devnum); 196 if (!dev_desc) { 197 printf("%s: Can't find dev_desc!\n", __func__); 198 return NULL; 199 } 200 201 #ifdef CONFIG_MMC 202 if (dev_type == IF_TYPE_MMC) { 203 struct mmc *mmc; 204 const char *timing[] = { 205 "Legacy", "High Speed", "High Speed", "SDR12", 206 "SDR25", "SDR50", "SDR104", "DDR50", 207 "DDR52", "HS200", "HS400", "HS400 Enhanced Strobe"}; 208 209 mmc = find_mmc_device(devnum); 210 printf("MMC%d: %s, %dMhz\n", devnum, 211 timing[mmc->timing], mmc->clock / 1000000); 212 } 213 #endif 214 215 printf("PartType: %s\n", part_get_type(dev_desc)); 216 217 return dev_desc; 218 } 219 220 void rockchip_set_bootdev(struct blk_desc *desc) 221 { 222 dev_desc = desc; 223 } 224 225 /* 226 * detect download key status by adc, most rockchip 227 * based boards use adc sample the download key status, 228 * but there are also some use gpio. So it's better to 229 * make this a weak function that can be override by 230 * some special boards. 231 */ 232 #define KEY_DOWN_MIN_VAL 0 233 #define KEY_DOWN_MAX_VAL 30 234 235 __weak int rockchip_dnl_key_pressed(void) 236 { 237 #if defined(CONFIG_DM_KEY) 238 return key_is_pressed(key_read(KEY_VOLUMEUP)); 239 240 #elif defined(CONFIG_ADC) 241 const void *blob = gd->fdt_blob; 242 int node, ret, channel = 1; 243 u32 val, chns[2]; 244 245 node = fdt_node_offset_by_compatible(blob, 0, "adc-keys"); 246 if (node >= 0) { 247 if (!fdtdec_get_int_array(blob, node, "io-channels", chns, 2)) 248 channel = chns[1]; 249 } 250 251 ret = adc_channel_single_shot("saradc", channel, &val); 252 if (ret) { 253 printf("%s: Failed to read saradc, ret=%d\n", __func__, ret); 254 return 0; 255 } 256 257 return ((val >= KEY_DOWN_MIN_VAL) && (val <= KEY_DOWN_MAX_VAL)); 258 #endif 259 260 return 0; 261 } 262 263 void setup_download_mode(void) 264 { 265 boot_devtype_init(); 266 267 /* recovery key or "ctrl+d" */ 268 if (rockchip_dnl_key_pressed() || is_hotkey(HK_ROCKUSB_DNL)) { 269 printf("download key pressed... "); 270 if (rockchip_u2phy_vbus_detect() > 0) { 271 printf("entering download mode...\n"); 272 /* try rockusb download and brom download */ 273 run_command("download", 0); 274 } else { 275 printf("entering recovery mode!\n"); 276 env_set("reboot_mode", "recovery-key"); 277 } 278 } else if (is_hotkey(HK_FASTBOOT)) { 279 env_set("reboot_mode", "fastboot"); 280 } 281 } 282 283 void board_run_recovery_wipe_data(void) 284 { 285 struct bootloader_message bmsg; 286 struct blk_desc *dev_desc; 287 disk_partition_t part_info; 288 #ifdef CONFIG_ANDROID_BOOT_IMAGE 289 u32 bcb_offset = android_bcb_msg_sector_offset(); 290 #else 291 u32 bcb_offset = BCB_MESSAGE_BLK_OFFSET; 292 #endif 293 int cnt, ret; 294 295 printf("Rebooting into recovery to do wipe_data\n"); 296 dev_desc = rockchip_get_bootdev(); 297 if (!dev_desc) { 298 printf("%s: dev_desc is NULL!\n", __func__); 299 return; 300 } 301 302 ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info); 303 if (ret < 0) { 304 printf("%s: Could not found misc partition, just run recovery\n", 305 __func__); 306 goto out; 307 } 308 309 memset((char *)&bmsg, 0, sizeof(struct bootloader_message)); 310 strcpy(bmsg.command, "boot-recovery"); 311 strcpy(bmsg.recovery, "recovery\n--wipe_data"); 312 bmsg.status[0] = 0; 313 cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), dev_desc->blksz); 314 ret = blk_dwrite(dev_desc, part_info.start + bcb_offset, cnt, &bmsg); 315 if (ret != cnt) 316 printf("Wipe data failed, ret=%d\n", ret); 317 out: 318 /* now reboot to recovery */ 319 env_set("reboot_mode", "recovery"); 320 run_command("run bootcmd", 0); 321 } 322