xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/boot_rkimg.c (revision fec9980f93fa667caac9706bb08d2001a63ea3e1)
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