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 using System;
8 using System.Linq;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Logging.Profiling;
14 using Antmicro.Renode.Peripherals.Bus;
15 using Antmicro.Renode.Peripherals.CPU;
16 using Antmicro.Renode.Peripherals.Memory;
17 using Antmicro.Renode.Utilities;
18 
19 namespace Antmicro.Renode.Peripherals.MTD
20 {
21     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)]
22     public class STM32H7_FlashController : STM32_FlashController, IKnownSize
23     {
STM32H7_FlashController(IMachine machine, MappedMemory flash1, MappedMemory flash2)24         public STM32H7_FlashController(IMachine machine, MappedMemory flash1, MappedMemory flash2) : base(machine)
25         {
26             bank1 = flash1;
27             bank2 = flash2;
28 
29             controlBank1Lock = new LockRegister(this, nameof(controlBank1Lock), ControlBankKey);
30             controlBank2Lock = new LockRegister(this, nameof(controlBank2Lock), ControlBankKey);
31             optionControlLock = new LockRegister(this, nameof(optionControlLock), OptionControlKey);
32 
33             DefineRegisters();
34             Reset();
35         }
36 
Reset()37         public override void Reset()
38         {
39             base.Reset();
40             controlBank1Lock.Reset();
41             controlBank2Lock.Reset();
42             optionControlLock.Reset();
43 
44             ProgramCurrentValues();
45         }
46 
WriteDoubleWord(long offset, uint value)47         public override void WriteDoubleWord(long offset, uint value)
48         {
49             if(optionControlLock.IsLocked && IsOffsetToProgramRegister(offset))
50             {
51                 this.Log(LogLevel.Warning, "Attempted to write to a program register ({0}) while OPTLOCK bit is set. Ignoring", Enum.GetName(typeof(Registers), (Registers)offset));
52                 return;
53             }
54             base.WriteDoubleWord(offset, value);
55         }
56 
57         public long Size => 0x1000;
58 
DefineRegisters()59         private void DefineRegisters()
60         {
61             // Software writes to this register and expects written value back during reads to work correctly
62             Registers.AccessControl.Define(this, 0x37)
63                 .WithValueField(0, 4, name: "LATENCY")
64                 .WithValueField(4, 2, name: "WRHIGHFREQ")
65                 .WithReservedBits(6, 26);
66 
67             Registers.KeyBank1.Define(this)
68                 .WithValueField(0, 32, FieldMode.Write, name: "FLASH_KEYR1",
69                     writeCallback: (_, value) => controlBank1Lock.ConsumeValue((uint)value));
70 
71             Registers.OptionKey.Define(this)
72                 .WithValueField(0, 32, FieldMode.Write, name: "FLASH_OPTKEYR",
73                     writeCallback: (_, value) => optionControlLock.ConsumeValue((uint)value));
74 
75             Registers.ControlBank1.Define(this, 0x31)
76                 .WithFlag(0, FieldMode.Read | FieldMode.Set, name: "LOCK1", valueProviderCallback: _ => controlBank1Lock.IsLocked,
77                     changeCallback: (_, value) =>
78                     {
79                         if(value)
80                         {
81                             controlBank1Lock.Lock();
82                         }
83                     })
84                 .WithTaggedFlag("PG1", 1)
85                 .WithTaggedFlag("SER1", 2)
86                 .WithTaggedFlag("BER1", 3)
87                 .WithTag("PSIZE1", 4, 2)
88                 .WithTaggedFlag("FW1", 6)
89                 .WithTaggedFlag("START1", 7)
90                 .WithTag("SNB1", 8, 3)
91                 .WithReservedBits(11, 4)
92                 .WithTaggedFlag("CRC_EN", 15)
93                 .WithTaggedFlag("EOPIE1", 16)
94                 .WithTaggedFlag("WRPERRIE1", 17)
95                 .WithTaggedFlag("PGSERRIE1", 18)
96                 .WithTaggedFlag("STRBERRIE1", 19)
97                 .WithReservedBits(20, 1)
98                 .WithTaggedFlag("INCERRIE1", 21)
99                 .WithTaggedFlag("OPERRIE1", 22)
100                 .WithTaggedFlag("RDPERRIE1", 23)
101                 .WithTaggedFlag("RDSERRIE1", 24)
102                 .WithTaggedFlag("SNECCERRIE1", 25)
103                 .WithTaggedFlag("DBECCERRIE1", 26)
104                 .WithTaggedFlag("CRCENDIE1", 27)
105                 .WithTaggedFlag("CRCRDERRIE1", 28)
106                 .WithReservedBits(29, 3);
107 
108             Registers.OptionControl.Define(this, 0x1)
109                 .WithFlag(0, FieldMode.Read | FieldMode.Set, name: "OPTLOCK", valueProviderCallback: _ => optionControlLock.IsLocked,
110                     changeCallback: (_, value) =>
111                     {
112                         if(value)
113                         {
114                             optionControlLock.Lock();
115                         }
116                     })
117                 .WithFlag(1, FieldMode.Write, name: "OPTSTART", writeCallback: (_, value) =>
118                     {
119                         if(!value)
120                         {
121                             return;
122                         }
123 
124                         if(optionControlLock.IsLocked)
125                         {
126                             this.Log(LogLevel.Warning, "Trying to start option byte change operation while the controller is locked. Ignoring");
127                             return;
128                         }
129 
130                         ProgramCurrentValues();
131                     })
132                 .WithReservedBits(2, 2)
133                 .WithTaggedFlag("MER", 4)
134                 .WithReservedBits(5, 25)
135                 .WithTaggedFlag("OPTCHANGEERRIE", 30)
136                 .WithTaggedFlag("SWAP_BANK", 31);
137 
138             Registers.OptionStatusCurrent.Define(this)
139                 .WithValueField(0, 32, FieldMode.Read, name: "FLASH_OPTSR_CUR", valueProviderCallback: _ => optionStatusCurrentValue);
140 
141             Registers.OptionStatusProgram.Define(this, 0x406AAF0, false)
142                 .WithValueField(0, 32, out optionStatusProgramRegister, name: "FLASH_OPTSR_PRG", softResettable: false);
143 
144             Registers.WriteSectorProtectionCurrentBank1.Define(this)
145                 .WithValueField(0, 8, FieldMode.Read, name: "WRPSn1", valueProviderCallback: _ => bank1WriteProtectionCurrentValue)
146                 .WithReservedBits(8, 24);
147 
148             Registers.WriteSectorProtectionProgramBank1.Define(this, 0xFF, false)
149                 .WithValueField(0, 8, out bank1WriteProtectionProgramRegister, name: "WRPSn1", softResettable: false)
150                 .WithReservedBits(8, 24);
151 
152             Registers.KeyBank2.Define(this)
153                 .WithValueField(0, 32, FieldMode.Write, name: "FLASH_KEYR2",
154                     writeCallback: (_, value) => controlBank2Lock.ConsumeValue((uint)value));
155 
156             Registers.ControlBank2.Define(this, 0x31)
157                 .WithFlag(0, FieldMode.Read | FieldMode.Set, name: "LOCK2", valueProviderCallback: _ => controlBank2Lock.IsLocked,
158                     changeCallback: (_, value) =>
159                     {
160                         if(value)
161                         {
162                             controlBank2Lock.Lock();
163                         }
164                     })
165                 .WithTaggedFlag("PG1", 1)
166                 .WithTaggedFlag("SER1", 2)
167                 .WithTaggedFlag("BER1", 3)
168                 .WithTag("PSIZE1", 4, 2)
169                 .WithTaggedFlag("FW1", 6)
170                 .WithTaggedFlag("START1", 7)
171                 .WithTag("SNB1", 8, 3)
172                 .WithReservedBits(11, 4)
173                 .WithTaggedFlag("CRC_EN", 15)
174                 .WithTaggedFlag("EOPIE1", 16)
175                 .WithTaggedFlag("WRPERRIE1", 17)
176                 .WithTaggedFlag("PGSERRIE1", 18)
177                 .WithTaggedFlag("STRBERRIE1", 19)
178                 .WithReservedBits(20, 1)
179                 .WithTaggedFlag("INCERRIE1", 21)
180                 .WithTaggedFlag("OPERRIE1", 22)
181                 .WithTaggedFlag("RDPERRIE1", 23)
182                 .WithTaggedFlag("RDSERRIE1", 24)
183                 .WithTaggedFlag("SNECCERRIE1", 25)
184                 .WithTaggedFlag("DBECCERRIE1", 26)
185                 .WithTaggedFlag("CRCENDIE1", 27)
186                 .WithTaggedFlag("CRCRDERRIE1", 28)
187                 .WithReservedBits(29, 3);
188 
189             Registers.WriteSectorProtectionCurrentBank2.Define(this)
190                 .WithValueField(0, 8, FieldMode.Read, name: "WRPSn2", valueProviderCallback: _ => bank2WriteProtectionCurrentValue)
191                 .WithReservedBits(8, 24);
192 
193             Registers.WriteSectorProtectionProgramBank2.Define(this, 0xFF, false)
194                 .WithValueField(0, 8, out bank2WriteProtectionProgramRegister, name: "WRPSn2", softResettable: false)
195                 .WithReservedBits(8, 24);
196         }
197 
ProgramCurrentValues()198         private void ProgramCurrentValues()
199         {
200             optionStatusCurrentValue = (uint)optionStatusProgramRegister.Value;
201             bank1WriteProtectionCurrentValue = (byte)bank1WriteProtectionProgramRegister.Value;
202             bank2WriteProtectionCurrentValue = (byte)bank2WriteProtectionProgramRegister.Value;
203         }
204 
IsOffsetToProgramRegister(long offset)205         private bool IsOffsetToProgramRegister(long offset)
206         {
207             switch((Registers)offset)
208             {
209                 case Registers.ProtectionAddressProgramBank1:
210                 case Registers.ProtectionAddressProgramBank2:
211                 case Registers.BootAddressProgram:
212                 case Registers.OptionStatusProgram:
213                 case Registers.SecureAddressProgramBank1:
214                 case Registers.SecureAddressProgramBank2:
215                 case Registers.WriteSectorProtectionProgramBank1:
216                 case Registers.WriteSectorProtectionProgramBank2:
217                     return true;
218                 default:
219                     return false;
220             }
221         }
222 
223         private uint optionStatusCurrentValue;
224         private byte bank1WriteProtectionCurrentValue;
225         private byte bank2WriteProtectionCurrentValue;
226 
227         private IValueRegisterField optionStatusProgramRegister;
228         private IValueRegisterField bank1WriteProtectionProgramRegister;
229         private IValueRegisterField bank2WriteProtectionProgramRegister;
230 
231         private readonly MappedMemory bank1;
232         private readonly MappedMemory bank2;
233 
234         private readonly LockRegister controlBank1Lock;
235         private readonly LockRegister controlBank2Lock;
236         private readonly LockRegister optionControlLock;
237 
238         private static readonly uint[] ControlBankKey = {0x45670123, 0xCDEF89AB};
239         private static readonly uint[] OptionControlKey = {0x08192A3B, 0x4C5D6E7F};
240 
241         private enum Registers
242         {
243             AccessControl = 0x000,                      // FLASH_ACR
244             KeyBank1 = 0x004,                           // FLASH_KEYR1
245             OptionKey = 0x008,                          // FLASH_OPTKEYR
246             ControlBank1 = 0x00C,                       // FLASH_CR1
247             StatusBank1 = 0x010,                        // FLASH_SR1
248             ClearControlBank1 = 0x014,                  // FLASH_CCR1
249             OptionControl = 0x018,                      // FLASH_OPTCR
250             OptionStatusCurrent = 0x01C,                // FLASH_OPTSR_CUR
251             OptionStatusProgram = 0x020,                // FLASH_OPTSR_PRG
252             OptionClearControl = 0x024,                 // FLASH_OPTCCR
253             ProtectionAddressCurrentBank1 = 0x028,      // FLASH_PRAR_CUR1
254             ProtectionAddressProgramBank1 = 0x02C,      // FLASH_PRAR_PRG1
255             SecureAddressCurrentBank1 = 0x030,          // FLASH_SCAR_CUR1
256             SecureAddressProgramBank1 = 0x034,          // FLASH_SCAR_PRG1
257             WriteSectorProtectionCurrentBank1 = 0x038,  // FLASH_WPSN_CUR1R
258             WriteSectorProtectionProgramBank1 = 0x03C,  // FLASH_WPSN_PRG1R
259             BootAddressCurrent = 0x040,                 // FLASH_BOOT_CURR
260             BootAddressProgram = 0x044,                 // FLASH_BOOT_PRGR
261             CRCControlBank1 = 0x050,                    // FLASH_CRCCR1
262             CRCStartAddressBank1 = 0x054,               // FLASH_CRCSADD1R
263             CRCEndAddressBank1 = 0x058,                 // FLASH_CRCEADD1R
264             CRCData = 0x05C,                            // FLASH_CRCDATAR
265             ECCFailAddressBank1 = 0x060,                // FLASH_ECC_FA1R
266             KeyBank2 = 0x104,                           // FLASH_KEYR2
267             ControlBank2 = 0x10C,                       // FLASH_CR2
268             StatusBank2 = 0x110,                        // FLASH_SR2
269             ClearControlBank2 = 0x114,                  // FLASH_CCR2
270             ProtectionAddressCurrentBank2 = 0x128,      // FLASH_PRAR_CUR2
271             ProtectionAddressProgramBank2 = 0x12C,      // FLASH_PRAR_PRG2
272             SecureAddressCurrentBank2 = 0x130,          // FLASH_SCAR_CUR2
273             SecureAddressProgramBank2 = 0x134,          // FLASH_SCAR_PRG2
274             WriteSectorProtectionCurrentBank2 = 0x138,  // FLASH_WPSN_CUR2R
275             WriteSectorProtectionProgramBank2 = 0x13C,  // FLASH_WPSN_PRG2R
276             CRCControlBank2 = 0x150,                    // FLASH_CRCCR2
277             CRCStartAddressBank2 = 0x154,               // FLASH_CRCSADD2R
278             CRCEndAddressBank2 = 0x158,                 // FLASH_CRCEADD2R
279             ECCFailAddressBank2 = 0x160,                // FLASH_ECC_FA2R
280         }
281     }
282 }
283