1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2019 NXP
4  */
5 
6 #include <common.h>
7 #include <console.h>
8 #include <errno.h>
9 #include <fuse.h>
10 #include <asm/arch/sci/sci.h>
11 #include <asm/arch/sys_proto.h>
12 #include <asm/global_data.h>
13 #include <linux/arm-smccc.h>
14 
15 DECLARE_GLOBAL_DATA_PTR;
16 
17 #define FSL_ECC_WORD_START_1	 0x10
18 #define FSL_ECC_WORD_END_1	 0x10F
19 
20 #ifdef CONFIG_IMX8QM
21 #define FSL_ECC_WORD_START_2	 0x1A0
22 #define FSL_ECC_WORD_END_2	 0x1FF
23 #elif defined(CONFIG_IMX8QXP)
24 #define FSL_ECC_WORD_START_2	 0x220
25 #define FSL_ECC_WORD_END_2	 0x31F
26 #endif
27 
28 #define FSL_QXP_FUSE_GAP_START	 0x110
29 #define FSL_QXP_FUSE_GAP_END	 0x21F
30 
31 #define FSL_SIP_OTP_READ             0xc200000A
32 #define FSL_SIP_OTP_WRITE            0xc200000B
33 
fuse_read(u32 bank,u32 word,u32 * val)34 int fuse_read(u32 bank, u32 word, u32 *val)
35 {
36 	return fuse_sense(bank, word, val);
37 }
38 
fuse_sense(u32 bank,u32 word,u32 * val)39 int fuse_sense(u32 bank, u32 word, u32 *val)
40 {
41 	struct arm_smccc_res res;
42 
43 	if (bank != 0) {
44 		printf("Invalid bank argument, ONLY bank 0 is supported\n");
45 		return -EINVAL;
46 	}
47 
48 	arm_smccc_smc(FSL_SIP_OTP_READ, (unsigned long)word, 0, 0,
49 		      0, 0, 0, 0, &res);
50 	*val = (u32)res.a1;
51 
52 	return res.a0;
53 }
54 
fuse_prog(u32 bank,u32 word,u32 val)55 int fuse_prog(u32 bank, u32 word, u32 val)
56 {
57 	struct arm_smccc_res res;
58 
59 	if (bank != 0) {
60 		printf("Invalid bank argument, ONLY bank 0 is supported\n");
61 		return -EINVAL;
62 	}
63 
64 	if (IS_ENABLED(CONFIG_IMX8QXP)) {
65 		if (word >= FSL_QXP_FUSE_GAP_START &&
66 		    word <= FSL_QXP_FUSE_GAP_END) {
67 			printf("Invalid word argument for this SoC\n");
68 			return -EINVAL;
69 		}
70 	}
71 
72 	if ((word >= FSL_ECC_WORD_START_1 && word <= FSL_ECC_WORD_END_1) ||
73 	    (word >= FSL_ECC_WORD_START_2 && word <= FSL_ECC_WORD_END_2)) {
74 		puts("Warning: Words in this index range have ECC protection\n"
75 		     "and can only be programmed once per word. Individual bit\n"
76 		     "operations will be rejected after the first one.\n"
77 		     "\n\n Really program this word? <y/N>\n");
78 
79 		if (!confirm_yesno()) {
80 			puts("Word programming aborted\n");
81 			return -EPERM;
82 		}
83 	}
84 
85 	arm_smccc_smc(FSL_SIP_OTP_WRITE, (unsigned long)word,
86 		      (unsigned long)val, 0, 0, 0, 0, 0, &res);
87 
88 	return res.a0;
89 }
90 
fuse_override(u32 bank,u32 word,u32 val)91 int fuse_override(u32 bank, u32 word, u32 val)
92 {
93 	printf("Override fuse to i.MX8 in u-boot is forbidden\n");
94 	return -EPERM;
95 }
96