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