1 //
2 // Copyright (c) 2010-2023 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 using System;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Utilities;
14 
15 namespace Antmicro.Renode.Peripherals.Miscellaneous
16 {
17     public class OpenTitan_LifeCycleController: BasicDoubleWordPeripheral, IKnownSize
18     {
OpenTitan_LifeCycleController(IMachine machine, OpenTitan_ResetManager resetManager, OpenTitan_OneTimeProgrammableMemoryController otpController)19         public OpenTitan_LifeCycleController(IMachine machine, OpenTitan_ResetManager resetManager, OpenTitan_OneTimeProgrammableMemoryController otpController) : base(machine)
20         {
21             this.resetManager = resetManager;
22             this.otpController = otpController;
23 
24             rmaToken = new byte[TokenRegistersCount * 4] ;
25             deviceId = new byte[DeviceIdRegistersCount * 4];
26             testExitToken = new byte[TokenRegistersCount * 4] ;
27             testUnlockToken = new byte[TokenRegistersCount * 4] ;
28             token = new byte[TokenRegistersCount * 4];
29 
30             FatalProgAlert = new GPIO();
31             FatalStateAlert = new GPIO();
32             FatalBusAlert = new GPIO();
33 
34             DefineRegisters();
35             Reset();
36         }
37 
Reset()38         public override void Reset()
39         {
40             base.Reset();
41             FatalProgAlert.Unset();
42             FatalStateAlert.Unset();
43             FatalBusAlert.Unset();
44 
45             Array.Clear(token, 0, token.Length);
46             readyFlag.Value = true;
47         }
48 
49         public long Size => 0x1000;
50 
51         public GPIO FatalProgAlert { get; }
52         public GPIO FatalStateAlert { get; }
53         public GPIO FatalBusAlert { get; }
54 
55         public string TestExitToken
56         {
57             set
58             {
59                 testExitToken = Misc.HexStringToByteArray(value);
60             }
61         }
62 
63         public string TestUnlockToken
64         {
65             set
66             {
67                 testUnlockToken = Misc.HexStringToByteArray(value);
68             }
69         }
70 
71         public string RMAToken
72         {
73             set
74             {
75                 rmaToken = Misc.HexStringToByteArray(value);
76             }
77         }
78 
79         public string DeviceId
80         {
81             get
82             {
83                 return deviceIdString;
84             }
85             set
86             {
87                 // This array was reversed to comply with the OpenTitan tests suite - the spec does not specify this
88                 deviceId = Misc.HexStringToByteArray(value).Reverse().ToArray();
89                 var otpDeviceId = otpController.GetOtpItem(OpenTitan_OneTimeProgrammableMemoryController.OtpItem.DeviceId);
90                 // Only print the warning message if otpDeviceId is set.
91                 if(deviceId != otpDeviceId && !otpDeviceId.All(o => o == 0))
92                 {
93                     var otpDeviceIdString = string.Join("", otpDeviceId);
94                     this.Log(LogLevel.Warning, "The set DeviceId differs from the one stored in the OTP Controller. Set: {0}, OTP:{1}",
95                              value, otpDeviceIdString);
96                 }
97                 deviceIdString = value;
98             }
99         }
100 
DefineRegisters()101         private void DefineRegisters()
102         {
103             Registers.AlertTest.Define(this)
104                 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalProgAlert.Blink(); }, name: "fatal_prog_error")
105                 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalStateAlert.Blink(); }, name: "fatal_state_error")
106                 .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalBusAlert.Blink(); }, name: "fatal_bus_integ_error")
107                 .WithIgnoredBits(3, 32 - 3);
108 
109             Registers.Status.Define(this)
110                 .WithFlag(0, out readyFlag, FieldMode.Read, name: "READY")
111                 .WithFlag(1, out transitionSuccesfulFlag, FieldMode.Read, name: "TRANSITION_SUCCESSFUL")
112                 .WithFlag(2, out transitionCountErorFlag, FieldMode.Read, name: "TRANSITION_COUNT_ERROR")
113                 .WithFlag(3, out transitionErrorFlag, FieldMode.Read, name: "TRANSITION_ERROR")
114                 .WithFlag(4, out tokenErrorFlag, FieldMode.Read, name: "TOKEN_ERROR")
115                 .WithTaggedFlag("FLASH_RMA_ERROR", 5)
116                 .WithTaggedFlag("OTP_ERROR", 6)
117                 .WithTaggedFlag("STATE_ERROR", 7)
118                 .WithTaggedFlag("OTP_PARTITION_ERROR", 8)
119                 .WithIgnoredBits(9, 32 - 9);
120 
121             Registers.ClaimTransitionIf.Define(this, (uint)MutexState.MultiBitFalse)
122                 .WithEnumField<DoubleWordRegister, MutexState>(0, 8, out mutexState,
123                     writeCallback: (_, val) =>
124                     {
125                         if(val == MutexState.MultiBitTrue)
126                         {
127                             if(mutexClaimed)
128                             {
129                                 mutexState.Value = MutexState.Taken;
130                             }
131                             else
132                             {
133                                 mutexClaimed = true;
134                                 transitionRegisterWriteEnable.Value = true;
135                             }
136                         }
137                     }, name: "MUTEX")
138                 .WithIgnoredBits(8, 32 - 8);
139 
140             Registers.TransitionRegisterWriteEnable.Define(this)
141                 .WithFlag(0, out transitionRegisterWriteEnable, name: "TRANSITION_REGWEN")
142                 .WithIgnoredBits(1, 32 - 1);
143 
144             Registers.TransitionCommand.Define(this)
145                 .WithFlag(0, FieldMode.WriteOneToClear, writeCallback: (_, val) => { if(val) ExecuteTransition(); }, name: "START")
146                 .WithIgnoredBits(1, 32 - 1);
147 
148             Registers.TransitionControl.Define(this)
149                 .WithFlag(0, name: "EXT_CLOCK_EN")
150                 .WithIgnoredBits(1, 32 - 1);
151 
152             Registers.TransitionToken0.DefineMany(this, TokenRegistersCount, (register, idx) =>
153             {
154                 register.WithValueField(0, 32,
155                                         writeCallback: (_, val) => Misc.ByteArrayWrite(idx * 4, (uint)val, token),
156                                         valueProviderCallback: (_) => Misc.ByteArrayRead(idx * 4, token), name: $"TRANSITION_TOKEN_{idx}");
157             });
158 
159             Registers.TransitionTarget.Define(this)
160                 .WithEnumField<DoubleWordRegister, TransitionTargetState>(0, 30, out transitionTarget, name: "STATE")
161                 .WithIgnoredBits(30, 2);
162 
163             Registers.OtpVendorTestControl.Define(this)
164                 .WithValueField(0, 32, name: "OTP_VENDOR_TEST_CTRL");
165 
166             Registers.OtpVendorTestStatus.Define(this)
167                 .WithValueField(0, 32, FieldMode.Read, name: "OTP_VENDOR_TEST_STATUS");
168 
169             Registers.LifeCycleState.Define(this)
170                 .WithEnumField<DoubleWordRegister, OpenTitan_LifeCycleState>(0, 30, FieldMode.Read, valueProviderCallback: _ => otpController.LifeCycleState, name: "STATE")
171                 .WithIgnoredBits(30, 32 - 30);
172 
173             Registers.LifeCycleTransitionCounter.Define(this)
174                 .WithValueField(0, 5, FieldMode.Read, valueProviderCallback: _ => otpController.LifeCycleTransitionCount, name: "COUNT")
175                 .WithIgnoredBits(5, 32 - 5);
176 
177             Registers.LifeCycleIdState.Define(this)
178                 .WithEnumField<DoubleWordRegister, IdState>(0, 32, FieldMode.Read, name: "STATE");
179 
180             Registers.HardwareRevision.Define(this)
181                 .WithTag("CHIP_REV", 0, 16)
182                 .WithTag("CHIP_GEN", 16, 16);
183 
184             Registers.DeviceId0.DefineMany(this, DeviceIdRegistersCount, (register, idx) =>
185             {
186                 register.WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => Misc.ByteArrayRead(idx * 4, deviceId), name: $"DEVICE_ID_{idx}");
187             });
188 
189             Registers.ManufacturingState0.DefineMany(this, ManufacturingStateRegistersCount, (register, idx) =>
190             {
191                 register.WithTag($"MANUF_STATE_{idx}", 0, 32);
192             });
193         }
194 
ExecuteTransition()195         private void ExecuteTransition()
196         {
197             var currentState = otpController.LifeCycleState;
198             var nextState = (OpenTitan_LifeCycleState)transitionTarget.Value;
199 
200             ClearStatusFlags();
201 
202             // Every transition attempt increments the count
203             otpController.IncrementTransitionCount();
204 
205             if(!IsTransitionAllowed(currentState, nextState))
206             {
207                 transitionErrorFlag.Value = true;
208                 this.Log(LogLevel.Warning, "Transitions between states {0} and {1} is not allowed.", currentState, nextState);
209                 return;
210             }
211             if(!IsTransitionTokenValid(currentState, nextState))
212             {
213                 tokenErrorFlag.Value = true;
214                 this.Log(LogLevel.Warning, "Invalid token for transition between states {0} and {1}.", currentState, nextState);
215                 return;
216             }
217 
218             otpController.LifeCycleState = nextState;
219             resetManager.LifeCycleReset();
220             transitionSuccesfulFlag.Value = true;
221         }
222 
ClearStatusFlags()223         private void ClearStatusFlags()
224         {
225             transitionSuccesfulFlag.Value = false;
226             transitionCountErorFlag.Value = false;
227             transitionErrorFlag.Value = false;
228             tokenErrorFlag.Value = false;
229         }
230 
IsTransitionAllowed(OpenTitan_LifeCycleState currentState, OpenTitan_LifeCycleState nextState)231         private bool IsTransitionAllowed(OpenTitan_LifeCycleState currentState, OpenTitan_LifeCycleState nextState)
232         {
233             if(nextState == OpenTitan_LifeCycleState.Scrap ||
234                currentState == OpenTitan_LifeCycleState.Raw && UnlockedTestStates.Contains(nextState))
235             {
236                 return true;
237             }
238             else if(UnlockedTestStates.Contains(currentState))
239             {
240                 if(LockedTestStates.Contains(nextState) && (nextState > currentState) ||
241                    nextState == OpenTitan_LifeCycleState.Rma ||
242                    MissionStates.Contains(nextState))
243                 {
244                     return true;
245                 }
246             }
247             else if((currentState == OpenTitan_LifeCycleState.Dev || currentState == OpenTitan_LifeCycleState.Prod) &&
248                     nextState == OpenTitan_LifeCycleState.Rma)
249             {
250                 return true;
251             }
252             return false;
253         }
254 
IsTransitionTokenValid(OpenTitan_LifeCycleState currentState, OpenTitan_LifeCycleState nextState)255         private bool IsTransitionTokenValid(OpenTitan_LifeCycleState currentState, OpenTitan_LifeCycleState nextState)
256         {
257             if(LockedTestStates.Contains(currentState) && UnlockedTestStates.Contains(nextState))
258             {
259                 return token.SequenceEqual(testUnlockToken);
260             }
261             else if(UnlockedTestStates.Contains(currentState) && MissionStates.Contains(nextState))
262             {
263                 return token.SequenceEqual(testExitToken);
264             }
265             else if(MissionStates.Contains(currentState) && nextState == OpenTitan_LifeCycleState.Rma)
266             {
267                 return token.SequenceEqual(rmaToken);
268             }
269             // No token required for this transition
270             return true;
271         }
272 
273         IEnumRegisterField<TransitionTargetState> transitionTarget;
274         IEnumRegisterField<MutexState> mutexState;
275         IFlagRegisterField readyFlag;
276         IFlagRegisterField transitionSuccesfulFlag;
277         IFlagRegisterField transitionRegisterWriteEnable;
278         IFlagRegisterField transitionCountErorFlag;
279         IFlagRegisterField transitionErrorFlag;
280         IFlagRegisterField tokenErrorFlag;
281 
282         private byte[] token;
283         private byte[] rmaToken;
284         private byte[] deviceId;
285         private byte[] testExitToken;
286         private byte[] testUnlockToken;
287 
288         private bool mutexClaimed;
289         private string deviceIdString;
290         private readonly OpenTitan_ResetManager resetManager;
291         private readonly OpenTitan_OneTimeProgrammableMemoryController otpController;
292 
293         private readonly OpenTitan_LifeCycleState[] MissionStates = { OpenTitan_LifeCycleState.Dev, OpenTitan_LifeCycleState.Prod, OpenTitan_LifeCycleState.Prod_end };
294         private readonly OpenTitan_LifeCycleState[] LockedTestStates = { OpenTitan_LifeCycleState.TestLocked0, OpenTitan_LifeCycleState.TestLocked1, OpenTitan_LifeCycleState.TestLocked2, OpenTitan_LifeCycleState.TestLocked3, OpenTitan_LifeCycleState.TestLocked4, OpenTitan_LifeCycleState.TestLocked5, OpenTitan_LifeCycleState.TestLocked6 };
295         private readonly OpenTitan_LifeCycleState[] UnlockedTestStates = { OpenTitan_LifeCycleState.TestUnlocked0, OpenTitan_LifeCycleState.TestUnlocked1, OpenTitan_LifeCycleState.TestUnlocked2, OpenTitan_LifeCycleState.TestUnlocked3, OpenTitan_LifeCycleState.TestUnlocked4, OpenTitan_LifeCycleState.TestUnlocked5, OpenTitan_LifeCycleState.TestUnlocked6, OpenTitan_LifeCycleState.TestUnlocked7 };
296 
297         private const uint TokenRegistersCount = 4;
298         private const uint DeviceIdRegistersCount = 8;
299         private const uint ManufacturingStateRegistersCount = 8;
300 
301         #pragma warning disable format
302         private enum IdState
303         {
304             Blank        = 0x00000000,
305             Personalized = 0x11111111,
306             Invalid      = 0x22222222,
307         }
308 
309         private enum MutexState
310         {
311             MultiBitTrue  = MultiBitBool8.True,
312             MultiBitFalse = MultiBitBool8.False,
313             Taken         = 0x00,
314         }
315 
316         // This is only a subset of the OpenTitan_LifeCycleState
317         private enum TransitionTargetState
318         {
319             Raw           = OpenTitan_LifeCycleState.Raw           ,  // Raw life cycle state after fabrication where all functions are disabled.
320             TestUnlocked0 = OpenTitan_LifeCycleState.TestUnlocked0 ,  // Unlocked test state where debug functions are enabled.
321             TestLocked0   = OpenTitan_LifeCycleState.TestLocked0   ,  // Locked test state where where all functions are disabled.
322             TestUnlocked1 = OpenTitan_LifeCycleState.TestUnlocked1 ,  // Unlocked test state where debug functions are enabled.
323             TestLocked1   = OpenTitan_LifeCycleState.TestLocked1   ,  // Locked test state where where all functions are disabled.
324             TestUnlocked2 = OpenTitan_LifeCycleState.TestUnlocked2 ,  // Unlocked test state where debug functions are enabled.
325             TestLocked2   = OpenTitan_LifeCycleState.TestLocked2   ,  // Locked test state where debug all functions are disabled.
326             TestUnlocked3 = OpenTitan_LifeCycleState.TestUnlocked3 ,  // Unlocked test state where debug functions are enabled.
327             TestLocked3   = OpenTitan_LifeCycleState.TestLocked3   ,  // Locked test state where debug all functions are disabled.
328             TestUnlocked4 = OpenTitan_LifeCycleState.TestUnlocked4 ,  // Unlocked test state where debug functions are enabled.
329             TestLocked4   = OpenTitan_LifeCycleState.TestLocked4   ,  // Locked test state where debug all functions are disabled.
330             TestUnlocked5 = OpenTitan_LifeCycleState.TestUnlocked5 ,  // Unlocked test state where debug functions are enabled.
331             TestLocked5   = OpenTitan_LifeCycleState.TestLocked5   ,  // Locked test state where debug all functions are disabled.
332             TestUnlocked6 = OpenTitan_LifeCycleState.TestUnlocked6 ,  // Unlocked test state where debug functions are enabled.
333             TestLocked6   = OpenTitan_LifeCycleState.TestLocked6   ,  // Locked test state where debug all functions are disabled.
334             TestUnlocked7 = OpenTitan_LifeCycleState.TestUnlocked7 ,  // Unlocked test state where debug functions are enabled.
335             Dev           = OpenTitan_LifeCycleState.Dev           ,  // Development life cycle state where limited debug functionality is available.
336             Prod          = OpenTitan_LifeCycleState.Prod          ,  // Production life cycle state.
337             Prod_end      = OpenTitan_LifeCycleState.Prod_end      ,  // Same as PROD, but transition into RMA is not possible from this state.
338             Rma           = OpenTitan_LifeCycleState.Rma           ,  // RMA life cycle state.
339             Scrap         = OpenTitan_LifeCycleState.Scrap         ,  // SCRAP life cycle state where all functions are disabled.
340         }
341 
342         public enum Registers
343         {
344             AlertTest                     = 0x00,
345             Status                        = 0x04,
346             ClaimTransitionIf             = 0x08,
347             TransitionRegisterWriteEnable = 0x0C,
348             TransitionCommand             = 0x10,
349             TransitionControl             = 0x14,
350             TransitionToken0              = 0x18,
351             TransitionToken1              = 0x1C,
352             TransitionToken2              = 0x20,
353             TransitionToken3              = 0x24,
354             TransitionTarget              = 0x28,
355             OtpVendorTestControl          = 0x2C,
356             OtpVendorTestStatus           = 0x30,
357             LifeCycleState                = 0x34,
358             LifeCycleTransitionCounter    = 0x38,
359             LifeCycleIdState              = 0x3C,
360             HardwareRevision              = 0x40,
361             DeviceId0                     = 0x44,
362             DeviceId1                     = 0x48,
363             DeviceId2                     = 0x4C,
364             DeviceId3                     = 0x50,
365             DeviceId4                     = 0x54,
366             DeviceId5                     = 0x58,
367             DeviceId6                     = 0x5C,
368             DeviceId7                     = 0x60,
369             ManufacturingState0           = 0x64,
370             ManufacturingState1           = 0x68,
371             ManufacturingState2           = 0x6C,
372             ManufacturingState3           = 0x70,
373             ManufacturingState4           = 0x74,
374             ManufacturingState5           = 0x78,
375             ManufacturingState6           = 0x7C,
376             ManufacturingState7           = 0x80,
377         }
378         #pragma warning restore format
379     }
380 }
381