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