xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/boot_mode.c (revision 5a94b26492fd3ad20c580976e18e101b67d14e6e)
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 enum {
16 	PH = 0,	/* P: Priority, H: high, M: middle, L: low*/
17 	PM,
18 	PL,
19 };
20 
21 static int misc_require_recovery(u32 bcb_offset, int *bcb_recovery_msg)
22 {
23 	struct bootloader_message *bmsg;
24 	struct blk_desc *dev_desc;
25 	disk_partition_t part;
26 	int cnt, recovery = 0;
27 
28 	dev_desc = rockchip_get_bootdev();
29 	if (!dev_desc) {
30 		printf("dev_desc is NULL!\n");
31 		goto out;
32 	}
33 
34 	if (part_get_info_by_name(dev_desc, PART_MISC, &part) < 0) {
35 		printf("No misc partition\n");
36 		goto out;
37 	}
38 
39 	cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), dev_desc->blksz);
40 	bmsg = memalign(ARCH_DMA_MINALIGN, cnt * dev_desc->blksz);
41 	if (blk_dread(dev_desc, part.start + bcb_offset, cnt, bmsg) != cnt) {
42 		recovery = 0;
43 	} else {
44 		recovery = !strcmp(bmsg->command, "boot-recovery");
45 		if (bcb_recovery_msg) {
46 			if (!strcmp(bmsg->recovery, "recovery\n--rk_fwupdate\n"))
47 				*bcb_recovery_msg = BCB_MSG_RECOVERY_RK_FWUPDATE;
48 			else if (!strcmp(bmsg->recovery, "recovery\n--factory_mode=whole") ||
49 				 !strcmp(bmsg->recovery, "recovery\n--factory_mode=small"))
50 				*bcb_recovery_msg = BCB_MSG_RECOVERY_PCBA;
51 		}
52 	}
53 
54 	free(bmsg);
55 out:
56 	return recovery;
57 }
58 
59 int get_bcb_recovery_msg(void)
60 {
61 	int bcb_recovery_msg = BCB_MSG_RECOVERY_NONE;
62 #ifdef CONFIG_ANDROID_BOOT_IMAGE
63 	u32 bcb_offset = android_bcb_msg_sector_offset();
64 #else
65 	u32 bcb_offset = BCB_MESSAGE_BLK_OFFSET;
66 #endif
67 	misc_require_recovery(bcb_offset, &bcb_recovery_msg);
68 
69 	return bcb_recovery_msg;
70 }
71 
72 /*
73  * There are three ways to get reboot-mode:
74  *
75  * No1. Android BCB which is defined in misc.img (0KB or 16KB offset)
76  * No2. CONFIG_ROCKCHIP_BOOT_MODE_REG that supports "reboot xxx" commands
77  * No3. Env variable "reboot_mode" which is added by U-Boot
78  *
79  * Recovery mode from:
80  *	- Android BCB in misc.img
81  *	- "reboot recovery" command
82  *	- recovery key pressed without usb attach
83  */
84 int rockchip_get_boot_mode(void)
85 {
86 	static int boot_mode[] =		/* static */
87 		{ -EINVAL, -EINVAL, -EINVAL };
88 	static int bcb_offset = -EINVAL;	/* static */
89 	uint32_t reg_boot_mode;
90 	char *env_reboot_mode;
91 	int clear_boot_reg = 0;
92 	int recovery_msg = 0;
93 #ifdef CONFIG_ANDROID_BOOT_IMAGE
94 	u32 offset = android_bcb_msg_sector_offset();
95 #else
96 	u32 offset = BCB_MESSAGE_BLK_OFFSET;
97 #endif
98 
99 	/*
100 	 * Env variable "reboot_mode" which is added by U-Boot, reading ever time.
101 	 */
102 	env_reboot_mode = env_get("reboot_mode");
103 	if (env_reboot_mode) {
104 		if (!strcmp(env_reboot_mode, "recovery-key")) {
105 			printf("boot mode: recovery (key)\n");
106 			return BOOT_MODE_RECOVERY;
107 		} else if (!strcmp(env_reboot_mode, "recovery-usb")) {
108 			printf("boot mode: recovery (usb)\n");
109 			return BOOT_MODE_RECOVERY;
110 		} else if (!strcmp(env_reboot_mode, "recovery")) {
111 			printf("boot mode: recovery (env)\n");
112 			return BOOT_MODE_RECOVERY;
113 		} else if (!strcmp(env_reboot_mode, "fastboot")) {
114 			printf("boot mode: fastboot\n");
115 			return BOOT_MODE_BOOTLOADER;
116 		}
117 	}
118 
119 	/*
120 	 * Android BCB special handle:
121 	 *    Once the Android BCB offset changed, reinitalize "boot_mode[PM]".
122 	 *
123 	 * Background:
124 	 *    1. there are two Android BCB at the 0KB(google) and 16KB(rk)
125 	 *       offset in misc.img
126 	 *    2. Android image: return 0KB offset if image version >= 10,
127 	 *	 otherwise 16KB
128 	 *    3. Not Android image: return 16KB offset, eg: FIT image.
129 	 *
130 	 * To handle the cases of 16KB and 0KB, we reinitial boot_mode[PM] once
131 	 * Android BCB is changed.
132 	 *
133 	 * PH and PL is from boot mode register and reading once.
134 	 * PM is from misc.img and should be updated if BCB offset is changed.
135 	 * Return the boot mode according to priority: PH > PM > PL.
136 	 */
137 	if (bcb_offset != offset) {
138 		boot_mode[PM] = -EINVAL;
139 		bcb_offset = offset;
140 	}
141 
142 	/* directly return if there is already valid mode */
143 	if (boot_mode[PH] != -EINVAL)
144 		return boot_mode[PH];
145 	else if (boot_mode[PM] != -EINVAL)
146 		return boot_mode[PM];
147 	else if (boot_mode[PL] != -EINVAL)
148 		return boot_mode[PL];
149 
150 	/*
151 	 * Boot mode priority
152 	 *
153 	 * Anyway, we should set download boot mode as the highest priority, so:
154 	 * reboot loader/bootloader/fastboot > misc partition "recovery" > reboot xxx.
155 	 */
156 	reg_boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
157 	if (reg_boot_mode == BOOT_LOADER) {
158 		printf("boot mode: loader\n");
159 		boot_mode[PH] = BOOT_MODE_LOADER;
160 		clear_boot_reg = 1;
161 	} else if (reg_boot_mode == BOOT_DFU) {
162 		printf("boot mode: dfu\n");
163 		boot_mode[PH] = BOOT_MODE_DFU;
164 		clear_boot_reg = 1;
165 	} else if (reg_boot_mode == BOOT_FASTBOOT) {
166 		printf("boot mode: bootloader\n");
167 		boot_mode[PH] = BOOT_MODE_BOOTLOADER;
168 		clear_boot_reg = 1;
169 	} else if (misc_require_recovery(bcb_offset, &recovery_msg)) {
170 		printf("boot mode: recovery (misc)\n");
171 		boot_mode[PM] = BOOT_MODE_RECOVERY;
172 	} else {
173 		switch (reg_boot_mode) {
174 		case BOOT_NORMAL:
175 			printf("boot mode: normal\n");
176 			boot_mode[PL] = BOOT_MODE_NORMAL;
177 			clear_boot_reg = 1;
178 			break;
179 		case BOOT_RECOVERY:
180 			printf("boot mode: recovery (cmd)\n");
181 			boot_mode[PL] = BOOT_MODE_RECOVERY;
182 			clear_boot_reg = 1;
183 			break;
184 		case BOOT_UMS:
185 			printf("boot mode: ums\n");
186 			boot_mode[PL] = BOOT_MODE_UMS;
187 			clear_boot_reg = 1;
188 			break;
189 		case BOOT_CHARGING:
190 			printf("boot mode: charging\n");
191 			boot_mode[PL] = BOOT_MODE_CHARGING;
192 			clear_boot_reg = 1;
193 			break;
194 		case BOOT_PANIC:
195 			printf("boot mode: panic\n");
196 			boot_mode[PL] = BOOT_MODE_PANIC;
197 			break;
198 		case BOOT_WATCHDOG:
199 			printf("boot mode: watchdog\n");
200 			boot_mode[PL] = BOOT_MODE_WATCHDOG;
201 			break;
202 		default:
203 			printf("boot mode: None\n");
204 			boot_mode[PL] = BOOT_MODE_UNDEFINE;
205 		}
206 	}
207 
208 	/*
209 	 * We don't clear boot mode reg when its value stands for the reboot
210 	 * reason or others(in the future), the kernel will need and clear it.
211 	 */
212 	if (clear_boot_reg)
213 		writel(BOOT_NORMAL, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
214 
215 	if (boot_mode[PH] != -EINVAL)
216 		return boot_mode[PH];
217 	else if (boot_mode[PM] != -EINVAL)
218 		return boot_mode[PM];
219 	else
220 		return boot_mode[PL];
221 }
222 
223 int setup_boot_mode(void)
224 {
225 	char env_preboot[256] = {0};
226 
227 	switch (rockchip_get_boot_mode()) {
228 	case BOOT_MODE_BOOTLOADER:
229 		printf("enter fastboot!\n");
230 #if defined(CONFIG_FASTBOOT_FLASH_MMC_DEV)
231 		snprintf(env_preboot, 256,
232 				"setenv preboot; mmc dev %x; fastboot usb 0; ",
233 				CONFIG_FASTBOOT_FLASH_MMC_DEV);
234 #elif defined(CONFIG_FASTBOOT_FLASH_NAND_DEV)
235 		snprintf(env_preboot, 256,
236 				"setenv preboot; fastboot usb 0; ");
237 #endif
238 		env_set("preboot", env_preboot);
239 		break;
240 	case BOOT_MODE_UMS:
241 		printf("enter UMS!\n");
242 		env_set("preboot", "setenv preboot; ums mmc 0");
243 		break;
244 #if defined(CONFIG_CMD_DFU)
245 	case BOOT_MODE_DFU:
246 		printf("enter DFU!\n");
247 		env_set("preboot", "setenv preboot; dfu 0 ${devtype} ${devnum}; rbrom");
248 		break;
249 #endif
250 	case BOOT_MODE_LOADER:
251 		printf("enter Rockusb!\n");
252 		env_set("preboot", "setenv preboot; rockusb 0 ${devtype} ${devnum}; rbrom");
253 		break;
254 	case BOOT_MODE_CHARGING:
255 		printf("enter charging!\n");
256 		env_set("preboot", "setenv preboot; charge");
257 		break;
258 	}
259 
260 	return 0;
261 }
262