1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2592f4aedSMax Krummenacher /*
3592f4aedSMax Krummenacher  * Copyright (C) 2014-2016, Toradex AG
4592f4aedSMax Krummenacher  */
5592f4aedSMax Krummenacher 
6592f4aedSMax Krummenacher /*
7592f4aedSMax Krummenacher  * Helpers for i.MX OTP fusing during module production
8592f4aedSMax Krummenacher */
9592f4aedSMax Krummenacher 
10592f4aedSMax Krummenacher #include <common.h>
11592f4aedSMax Krummenacher #ifndef CONFIG_SPL_BUILD
12592f4aedSMax Krummenacher #include <console.h>
13592f4aedSMax Krummenacher #include <fuse.h>
14592f4aedSMax Krummenacher 
mfgr_fuse(void)15592f4aedSMax Krummenacher static int mfgr_fuse(void)
16592f4aedSMax Krummenacher {
17592f4aedSMax Krummenacher 	unsigned val, val6;
18592f4aedSMax Krummenacher 
19592f4aedSMax Krummenacher 	fuse_sense(0, 5, &val);
20592f4aedSMax Krummenacher 	printf("Fuse 0, 5: %8x\n", val);
21592f4aedSMax Krummenacher 	fuse_sense(0, 6, &val6);
22592f4aedSMax Krummenacher 	printf("Fuse 0, 6: %8x\n", val6);
23592f4aedSMax Krummenacher 	fuse_sense(4, 3, &val);
24592f4aedSMax Krummenacher 	printf("Fuse 4, 3: %8x\n", val);
25592f4aedSMax Krummenacher 	fuse_sense(4, 2, &val);
26592f4aedSMax Krummenacher 	printf("Fuse 4, 2: %8x\n", val);
27592f4aedSMax Krummenacher 	if (val6 & 0x10) {
28592f4aedSMax Krummenacher 		puts("BT_FUSE_SEL already fused, will do nothing\n");
29592f4aedSMax Krummenacher 		return CMD_RET_FAILURE;
30592f4aedSMax Krummenacher 	}
31592f4aedSMax Krummenacher 	/* boot cfg */
32592f4aedSMax Krummenacher 	fuse_prog(0, 5, 0x00005072);
33592f4aedSMax Krummenacher 	/* BT_FUSE_SEL */
34592f4aedSMax Krummenacher 	fuse_prog(0, 6, 0x00000010);
35592f4aedSMax Krummenacher 	return CMD_RET_SUCCESS;
36592f4aedSMax Krummenacher }
37592f4aedSMax Krummenacher 
do_mfgr_fuse(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])38592f4aedSMax Krummenacher int do_mfgr_fuse(cmd_tbl_t *cmdtp, int flag, int argc,
39592f4aedSMax Krummenacher 		char * const argv[])
40592f4aedSMax Krummenacher {
41592f4aedSMax Krummenacher 	int ret;
42592f4aedSMax Krummenacher 	puts("Fusing...\n");
43592f4aedSMax Krummenacher 	ret = mfgr_fuse();
44592f4aedSMax Krummenacher 	if (ret == CMD_RET_SUCCESS)
45592f4aedSMax Krummenacher 		puts("done.\n");
46592f4aedSMax Krummenacher 	else
47592f4aedSMax Krummenacher 		puts("failed.\n");
48592f4aedSMax Krummenacher 	return ret;
49592f4aedSMax Krummenacher }
50592f4aedSMax Krummenacher 
do_updt_fuse(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])51592f4aedSMax Krummenacher int do_updt_fuse(cmd_tbl_t *cmdtp, int flag, int argc,
52592f4aedSMax Krummenacher 		char * const argv[])
53592f4aedSMax Krummenacher {
54592f4aedSMax Krummenacher 	unsigned val;
55592f4aedSMax Krummenacher 	int ret;
56592f4aedSMax Krummenacher 	int confirmed = argc >= 1 && !strcmp(argv[1], "-y");
57592f4aedSMax Krummenacher 
58592f4aedSMax Krummenacher 	/* can be used in scripts for command availability check */
59592f4aedSMax Krummenacher 	if (argc >= 1 && !strcmp(argv[1], "-n"))
60592f4aedSMax Krummenacher 		return CMD_RET_SUCCESS;
61592f4aedSMax Krummenacher 
62592f4aedSMax Krummenacher 	/* boot cfg */
63592f4aedSMax Krummenacher 	fuse_sense(0, 5, &val);
64592f4aedSMax Krummenacher 	printf("Fuse 0, 5: %8x\n", val);
65592f4aedSMax Krummenacher 	if (val & 0x10) {
66592f4aedSMax Krummenacher 		puts("Fast boot mode already fused, no need to fuse\n");
67592f4aedSMax Krummenacher 		return CMD_RET_SUCCESS;
68592f4aedSMax Krummenacher 	}
69592f4aedSMax Krummenacher 	if (!confirmed) {
70592f4aedSMax Krummenacher 		puts("Warning: Programming fuses is an irreversible operation!\n"
71592f4aedSMax Krummenacher 				"         Updating to fast boot mode prevents easy\n"
72592f4aedSMax Krummenacher 				"         downgrading to previous BSP versions.\n"
73592f4aedSMax Krummenacher 				"\nReally perform this fuse programming? <y/N>\n");
74592f4aedSMax Krummenacher 		if (!confirm_yesno())
75592f4aedSMax Krummenacher 			return CMD_RET_FAILURE;
76592f4aedSMax Krummenacher 	}
77592f4aedSMax Krummenacher 	puts("Fusing fast boot mode...\n");
78592f4aedSMax Krummenacher 	ret = fuse_prog(0, 5, 0x00005072);
79592f4aedSMax Krummenacher 	if (ret == CMD_RET_SUCCESS)
80592f4aedSMax Krummenacher 		puts("done.\n");
81592f4aedSMax Krummenacher 	else
82592f4aedSMax Krummenacher 		puts("failed.\n");
83592f4aedSMax Krummenacher 	return ret;
84592f4aedSMax Krummenacher }
85592f4aedSMax Krummenacher 
86592f4aedSMax Krummenacher U_BOOT_CMD(
87592f4aedSMax Krummenacher 	mfgr_fuse, 1, 0, do_mfgr_fuse,
88592f4aedSMax Krummenacher 	"OTP fusing during module production",
89592f4aedSMax Krummenacher 	""
90592f4aedSMax Krummenacher );
91592f4aedSMax Krummenacher 
92592f4aedSMax Krummenacher U_BOOT_CMD(
93592f4aedSMax Krummenacher 	updt_fuse, 2, 0, do_updt_fuse,
94592f4aedSMax Krummenacher 	"OTP fusing during module update",
95592f4aedSMax Krummenacher 	"updt_fuse [-n] [-y] - boot cfg fast boot mode fusing"
96592f4aedSMax Krummenacher );
97592f4aedSMax Krummenacher #endif /* CONFIG_SPL_BUILD */
98