1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4 */
5
6 #include <command.h>
7 #include <fuse.h>
8 #include <misc.h>
9 #include <errno.h>
10 #include <dm/device.h>
11 #include <dm/uclass.h>
12 #include <power/stpmic1.h>
13
14 #define STM32MP_OTP_BANK 0
15 #define STM32MP_NVM_BANK 1
16
17 /*
18 * The 'fuse' command API
19 */
fuse_read(u32 bank,u32 word,u32 * val)20 int fuse_read(u32 bank, u32 word, u32 *val)
21 {
22 int ret;
23 struct udevice *dev;
24
25 switch (bank) {
26 case STM32MP_OTP_BANK:
27 ret = uclass_get_device_by_driver(UCLASS_MISC,
28 DM_DRIVER_GET(stm32mp_bsec),
29 &dev);
30 if (ret)
31 return ret;
32 ret = misc_read(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET,
33 val, 4);
34 if (ret != 4)
35 ret = -EINVAL;
36 else
37 ret = 0;
38 break;
39
40 #ifdef CONFIG_PMIC_STPMIC1
41 case STM32MP_NVM_BANK:
42 ret = uclass_get_device_by_driver(UCLASS_MISC,
43 DM_DRIVER_GET(stpmic1_nvm),
44 &dev);
45 if (ret)
46 return ret;
47 *val = 0;
48 ret = misc_read(dev, -word, val, 1);
49 if (ret != 1)
50 ret = -EINVAL;
51 else
52 ret = 0;
53 break;
54 #endif /* CONFIG_PMIC_STPMIC1 */
55
56 default:
57 printf("stm32mp %s: wrong value for bank %i\n", __func__, bank);
58 ret = -EINVAL;
59 break;
60 }
61
62 return ret;
63 }
64
fuse_prog(u32 bank,u32 word,u32 val)65 int fuse_prog(u32 bank, u32 word, u32 val)
66 {
67 struct udevice *dev;
68 int ret;
69
70 switch (bank) {
71 case STM32MP_OTP_BANK:
72 ret = uclass_get_device_by_driver(UCLASS_MISC,
73 DM_DRIVER_GET(stm32mp_bsec),
74 &dev);
75 if (ret)
76 return ret;
77 ret = misc_write(dev, word * 4 + STM32_BSEC_OTP_OFFSET,
78 &val, 4);
79 if (ret != 4)
80 ret = -EINVAL;
81 else
82 ret = 0;
83 break;
84
85 #ifdef CONFIG_PMIC_STPMIC1
86 case STM32MP_NVM_BANK:
87 ret = uclass_get_device_by_driver(UCLASS_MISC,
88 DM_DRIVER_GET(stpmic1_nvm),
89 &dev);
90 if (ret)
91 return ret;
92 ret = misc_write(dev, word, &val, 1);
93 if (ret != 1)
94 ret = -EINVAL;
95 else
96 ret = 0;
97 break;
98 #endif /* CONFIG_PMIC_STPMIC1 */
99
100 default:
101 printf("stm32mp %s: wrong value for bank %i\n", __func__, bank);
102 ret = -EINVAL;
103 break;
104 }
105
106 return ret;
107 }
108
fuse_sense(u32 bank,u32 word,u32 * val)109 int fuse_sense(u32 bank, u32 word, u32 *val)
110 {
111 struct udevice *dev;
112 int ret;
113
114 switch (bank) {
115 case STM32MP_OTP_BANK:
116 ret = uclass_get_device_by_driver(UCLASS_MISC,
117 DM_DRIVER_GET(stm32mp_bsec),
118 &dev);
119 if (ret)
120 return ret;
121 ret = misc_read(dev, word * 4 + STM32_BSEC_OTP_OFFSET, val, 4);
122 if (ret != 4)
123 ret = -EINVAL;
124 else
125 ret = 0;
126 break;
127
128 #ifdef CONFIG_PMIC_STPMIC1
129 case STM32MP_NVM_BANK:
130 ret = uclass_get_device_by_driver(UCLASS_MISC,
131 DM_DRIVER_GET(stpmic1_nvm),
132 &dev);
133 if (ret)
134 return ret;
135 *val = 0;
136 ret = misc_read(dev, word, val, 1);
137 if (ret != 1)
138 ret = -EINVAL;
139 else
140 ret = 0;
141 break;
142 #endif /* CONFIG_PMIC_STPMIC1 */
143
144 default:
145 printf("stm32mp %s: wrong value for bank %i\n", __func__, bank);
146 ret = -EINVAL;
147 break;
148 }
149
150 return ret;
151 }
152
fuse_override(u32 bank,u32 word,u32 val)153 int fuse_override(u32 bank, u32 word, u32 val)
154 {
155 struct udevice *dev;
156 int ret;
157
158 switch (bank) {
159 case STM32MP_OTP_BANK:
160 ret = uclass_get_device_by_driver(UCLASS_MISC,
161 DM_DRIVER_GET(stm32mp_bsec),
162 &dev);
163 if (ret)
164 return ret;
165 ret = misc_write(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET,
166 &val, 4);
167 if (ret != 4)
168 ret = -EINVAL;
169 else
170 ret = 0;
171 break;
172
173 #ifdef CONFIG_PMIC_STPMIC1
174 case STM32MP_NVM_BANK:
175 ret = uclass_get_device_by_driver(UCLASS_MISC,
176 DM_DRIVER_GET(stpmic1_nvm),
177 &dev);
178 if (ret)
179 return ret;
180 ret = misc_write(dev, -word, &val, 1);
181 if (ret != 1)
182 ret = -EINVAL;
183 else
184 ret = 0;
185 break;
186 #endif /* CONFIG_PMIC_STPMIC1 */
187
188 default:
189 printf("stm32mp %s: wrong value for bank %i\n",
190 __func__, bank);
191 ret = -EINVAL;
192 break;
193 }
194
195 return ret;
196 }
197