1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2a02d517bSMax Krummenacher /*
3a02d517bSMax Krummenacher  * Copyright (C) 2014-2016, Toradex AG
4a02d517bSMax Krummenacher  */
5a02d517bSMax Krummenacher 
6a02d517bSMax Krummenacher /*
7a02d517bSMax Krummenacher  * Helpers for i.MX OTP fusing during module production
8a02d517bSMax Krummenacher */
9a02d517bSMax Krummenacher 
10a02d517bSMax Krummenacher #include <common.h>
11a02d517bSMax Krummenacher #ifndef CONFIG_SPL_BUILD
12a02d517bSMax Krummenacher #include <console.h>
13a02d517bSMax Krummenacher #include <fuse.h>
14a02d517bSMax Krummenacher 
mfgr_fuse(void)15a02d517bSMax Krummenacher static int mfgr_fuse(void)
16a02d517bSMax Krummenacher {
17a02d517bSMax Krummenacher 	unsigned val, val6;
18a02d517bSMax Krummenacher 
19a02d517bSMax Krummenacher 	fuse_sense(0, 5, &val);
20a02d517bSMax Krummenacher 	printf("Fuse 0, 5: %8x\n", val);
21a02d517bSMax Krummenacher 	fuse_sense(0, 6, &val6);
22a02d517bSMax Krummenacher 	printf("Fuse 0, 6: %8x\n", val6);
23a02d517bSMax Krummenacher 	fuse_sense(4, 3, &val);
24a02d517bSMax Krummenacher 	printf("Fuse 4, 3: %8x\n", val);
25a02d517bSMax Krummenacher 	fuse_sense(4, 2, &val);
26a02d517bSMax Krummenacher 	printf("Fuse 4, 2: %8x\n", val);
27a02d517bSMax Krummenacher 	if (val6 & 0x10) {
28a02d517bSMax Krummenacher 		puts("BT_FUSE_SEL already fused, will do nothing\n");
29a02d517bSMax Krummenacher 		return CMD_RET_FAILURE;
30a02d517bSMax Krummenacher 	}
31a02d517bSMax Krummenacher 	/* boot cfg */
32a02d517bSMax Krummenacher 	fuse_prog(0, 5, 0x00005072);
33a02d517bSMax Krummenacher 	/* BT_FUSE_SEL */
34a02d517bSMax Krummenacher 	fuse_prog(0, 6, 0x00000010);
35a02d517bSMax Krummenacher 	return CMD_RET_SUCCESS;
36a02d517bSMax Krummenacher }
37a02d517bSMax Krummenacher 
do_mfgr_fuse(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])38a02d517bSMax Krummenacher int do_mfgr_fuse(cmd_tbl_t *cmdtp, int flag, int argc,
39a02d517bSMax Krummenacher 		char * const argv[])
40a02d517bSMax Krummenacher {
41a02d517bSMax Krummenacher 	int ret;
42a02d517bSMax Krummenacher 	puts("Fusing...\n");
43a02d517bSMax Krummenacher 	ret = mfgr_fuse();
44a02d517bSMax Krummenacher 	if (ret == CMD_RET_SUCCESS)
45a02d517bSMax Krummenacher 		puts("done.\n");
46a02d517bSMax Krummenacher 	else
47a02d517bSMax Krummenacher 		puts("failed.\n");
48a02d517bSMax Krummenacher 	return ret;
49a02d517bSMax Krummenacher }
50a02d517bSMax Krummenacher 
do_updt_fuse(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])51a02d517bSMax Krummenacher int do_updt_fuse(cmd_tbl_t *cmdtp, int flag, int argc,
52a02d517bSMax Krummenacher 		char * const argv[])
53a02d517bSMax Krummenacher {
54a02d517bSMax Krummenacher 	unsigned val;
55a02d517bSMax Krummenacher 	int ret;
56a02d517bSMax Krummenacher 	int confirmed = argc >= 1 && !strcmp(argv[1], "-y");
57a02d517bSMax Krummenacher 
58a02d517bSMax Krummenacher 	/* can be used in scripts for command availability check */
59a02d517bSMax Krummenacher 	if (argc >= 1 && !strcmp(argv[1], "-n"))
60a02d517bSMax Krummenacher 		return CMD_RET_SUCCESS;
61a02d517bSMax Krummenacher 
62a02d517bSMax Krummenacher 	/* boot cfg */
63a02d517bSMax Krummenacher 	fuse_sense(0, 5, &val);
64a02d517bSMax Krummenacher 	printf("Fuse 0, 5: %8x\n", val);
65a02d517bSMax Krummenacher 	if (val & 0x10) {
66a02d517bSMax Krummenacher 		puts("Fast boot mode already fused, no need to fuse\n");
67a02d517bSMax Krummenacher 		return CMD_RET_SUCCESS;
68a02d517bSMax Krummenacher 	}
69a02d517bSMax Krummenacher 	if (!confirmed) {
70a02d517bSMax Krummenacher 		puts("Warning: Programming fuses is an irreversible operation!\n"
71a02d517bSMax Krummenacher 				"         Updating to fast boot mode prevents easy\n"
72a02d517bSMax Krummenacher 				"         downgrading to previous BSP versions.\n"
73a02d517bSMax Krummenacher 				"\nReally perform this fuse programming? <y/N>\n");
74a02d517bSMax Krummenacher 		if (!confirm_yesno())
75a02d517bSMax Krummenacher 			return CMD_RET_FAILURE;
76a02d517bSMax Krummenacher 	}
77a02d517bSMax Krummenacher 	puts("Fusing fast boot mode...\n");
78a02d517bSMax Krummenacher 	ret = fuse_prog(0, 5, 0x00005072);
79a02d517bSMax Krummenacher 	if (ret == CMD_RET_SUCCESS)
80a02d517bSMax Krummenacher 		puts("done.\n");
81a02d517bSMax Krummenacher 	else
82a02d517bSMax Krummenacher 		puts("failed.\n");
83a02d517bSMax Krummenacher 	return ret;
84a02d517bSMax Krummenacher }
85a02d517bSMax Krummenacher 
86a02d517bSMax Krummenacher U_BOOT_CMD(
87a02d517bSMax Krummenacher 	mfgr_fuse, 1, 0, do_mfgr_fuse,
88a02d517bSMax Krummenacher 	"OTP fusing during module production",
89a02d517bSMax Krummenacher 	""
90a02d517bSMax Krummenacher );
91a02d517bSMax Krummenacher 
92a02d517bSMax Krummenacher U_BOOT_CMD(
93a02d517bSMax Krummenacher 	updt_fuse, 2, 0, do_updt_fuse,
94a02d517bSMax Krummenacher 	"OTP fusing during module update",
95a02d517bSMax Krummenacher 	"updt_fuse [-n] [-y] - boot cfg fast boot mode fusing"
96a02d517bSMax Krummenacher );
97a02d517bSMax Krummenacher #endif /* CONFIG_SPL_BUILD */
98