1 // 2 // Copyright (c) 2010-2024 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 STM32F4_FlashController : STM32_FlashController, IKnownSize 23 { STM32F4_FlashController(IMachine machine, MappedMemory flash)24 public STM32F4_FlashController(IMachine machine, MappedMemory flash) : base(machine) 25 { 26 this.flash = flash; 27 28 controlLock = new LockRegister(this, nameof(controlLock), ControlLockKey); 29 optionControlLock = new LockRegister(this, nameof(optionControlLock), OptionLockKey); 30 31 optionBytesRegisters = new DoubleWordRegisterCollection(this); 32 33 DefineRegisters(); 34 Reset(); 35 } 36 Reset()37 public override void Reset() 38 { 39 base.Reset(); 40 controlLock.Reset(); 41 optionControlLock.Reset(); 42 } 43 44 [ConnectionRegion("optionBytes")] ReadDoubleWordFromOptionBytes(long offset)45 public uint ReadDoubleWordFromOptionBytes(long offset) 46 { 47 uint value = optionBytesRegisters.Read(offset); 48 this.Log(LogLevel.Debug, "Reading from option bytes (offset: 0x{0:X} value: 0x{1:X8})", offset, value); 49 return value; 50 } 51 52 [ConnectionRegion("optionBytes")] WriteDoubleWordToOptionBytes(long offset, uint value)53 public void WriteDoubleWordToOptionBytes(long offset, uint value) 54 { 55 // This region is modified by using the OptionControl register. Direct modification is not allowed 56 this.Log(LogLevel.Error, "Attempt to write 0x{0:X8} to {1} in the option bytes region", value, offset); 57 } 58 WriteDoubleWord(long offset, uint value)59 public override void WriteDoubleWord(long offset, uint value) 60 { 61 if((Registers)offset == Registers.Control && controlLock.IsLocked) 62 { 63 this.Log(LogLevel.Warning, "Attempted to write 0x{0:X8} to a locked Control register. Ignoring...", value); 64 return; 65 } 66 67 if((Registers)offset == Registers.OptionControl && optionControlLock.IsLocked) 68 { 69 this.Log(LogLevel.Warning, "Attempted to write 0x{0:X8} to a locked OptionControl register. Ignoring...", value); 70 return; 71 } 72 73 base.WriteDoubleWord(offset, value); 74 } 75 76 public long Size => 0x400; 77 DefineRegisters()78 private void DefineRegisters() 79 { 80 Registers.AccessControl.Define(this) 81 //This field is written and read by software and we need to keep it's value. 82 .WithValueField(0, 4, name: "LATENCY") 83 .WithReservedBits(4, 4) 84 .WithTaggedFlag("PRFTEN", 8) 85 .WithTaggedFlag("ICEN", 9) 86 .WithTaggedFlag("DCEN", 10) 87 .WithTaggedFlag("ICRST", 11) 88 .WithTaggedFlag("DCRST", 12) 89 .WithReservedBits(13, 19); 90 91 Registers.Key.Define(this) 92 .WithValueField(0, 32, FieldMode.Write, name: "FLASH_KEYR", 93 writeCallback: (_, value) => controlLock.ConsumeValue((uint)value)); 94 95 Registers.OptionKey.Define(this) 96 .WithValueField(0, 32, FieldMode.Write, name: "FLASH_OPTKEYR", 97 writeCallback: (_, value) => optionControlLock.ConsumeValue((uint)value)); 98 99 Registers.Status.Define(this) 100 .WithTaggedFlag("EOP", 0) 101 .WithTaggedFlag("OPERR", 1) 102 .WithReservedBits(2, 2) 103 .WithTaggedFlag("WRPERR", 4) 104 .WithTaggedFlag("PGAERR", 5) 105 .WithTaggedFlag("PGPERR", 6) 106 .WithTaggedFlag("PGSERR", 7) 107 .WithTaggedFlag("RDERR", 8) 108 .WithReservedBits(9, 7) 109 .WithTaggedFlag("BSY", 16) 110 .WithReservedBits(17, 15); 111 112 Registers.Control.Define(this) 113 .WithTaggedFlag("PG", 0) 114 .WithFlag(1, out var sectorErase, name: "SER") 115 .WithFlag(2, out var massErase, name: "MER") 116 .WithValueField(3, 4, out var sectorNumber, name: "SNB") 117 .WithReservedBits(7, 1) 118 .WithTag("PSIZE", 8, 2) 119 .WithReservedBits(10, 6) 120 .WithFlag(16, out var startErase, name: "STRT", mode: FieldMode.Read | FieldMode.Set, valueProviderCallback: _ => false) 121 .WithReservedBits(17, 7) 122 .WithTaggedFlag("EOPIE", 24) 123 .WithTaggedFlag("ERRIE", 25) 124 .WithReservedBits(26, 5) 125 .WithFlag(31, FieldMode.Read | FieldMode.Set, name: "LOCK", valueProviderCallback: _ => controlLock.IsLocked, 126 changeCallback: (_, value) => 127 { 128 if(value) 129 { 130 controlLock.Lock(); 131 } 132 }) 133 .WithChangeCallback((_, __) => 134 { 135 if(startErase.Value) 136 { 137 Erase(massErase.Value, sectorErase.Value, (uint)sectorNumber.Value); 138 } 139 }); 140 141 Registers.OptionControl.Define(this, 0xFFFAAED) 142 .WithFlag(0, FieldMode.Read | FieldMode.Set, name: "OPTLOCK", valueProviderCallback: _ => optionControlLock.IsLocked, 143 changeCallback: (_, value) => 144 { 145 if (value) 146 { 147 optionControlLock.Lock(); 148 } 149 }) 150 .WithFlag(1, FieldMode.Read | FieldMode.Set, name: "OPTSTRT", changeCallback: (_, value) => 151 { 152 if(value) 153 { 154 readProtectionOptionBytes.Value = readProtectionRegister.Value; 155 writeProtectionOptionBytes.Value = writeProtectionRegister.Value; 156 } 157 }) 158 .WithTag("BOR_LEV", 2, 2) 159 .WithReservedBits(4, 1) 160 .WithTag("USER", 5, 2) 161 // According to the documentation those fields should be reloaded from flash memory at reset 162 // but it doesn't specify where they should be stored and how should they be saved 163 .WithValueField(8, 8, out readProtectionRegister, name: "RDP", softResettable: false) 164 .WithValueField(16, 12, out writeProtectionRegister, name: "nWRP", softResettable: false) 165 .WithReservedBits(28, 3) 166 .WithTaggedFlag("SPRMOD", 31); 167 168 OptionBytesRegisters.ReadProtectionAndUser.Define(optionBytesRegisters, 0xAAEC) 169 .WithReservedBits(0, 2) 170 .WithTag("BOR_LEV", 2, 2) 171 .WithReservedBits(4, 1) 172 .WithTaggedFlag("WDG_SW", 5) 173 .WithTaggedFlag("nRST_STOP", 6) 174 .WithTaggedFlag("nRST_STDBY", 7) 175 .WithValueField(8, 8, out readProtectionOptionBytes, name: "RDP") 176 .WithReservedBits(16, 16); 177 178 OptionBytesRegisters.WriteProtection.Define(optionBytesRegisters, 0xFFF) 179 .WithValueField(0, 12, out writeProtectionOptionBytes, name: "nWRPi") 180 .WithReservedBits(12, 3) 181 .WithTaggedFlag("SPRMOD", 15) 182 .WithReservedBits(16, 16); 183 } 184 Erase(bool massErase, bool sectorErase, uint sectorNumber)185 private void Erase(bool massErase, bool sectorErase, uint sectorNumber) 186 { 187 if(!massErase && !sectorErase) 188 { 189 this.Log(LogLevel.Warning, "Tried to erase flash, but MER and SER are reset. This should be forbidden, ignoring..."); 190 return; 191 } 192 193 if(massErase) 194 { 195 PerformMassErase(); 196 } 197 else 198 { 199 PerformSectorErase(sectorNumber); 200 } 201 } 202 PerformSectorErase(uint sectorNumber)203 private void PerformSectorErase(uint sectorNumber) 204 { 205 if(!Sectors.ContainsKey(sectorNumber)) 206 { 207 this.Log(LogLevel.Warning, "Tried to erase sector {0}, which doesn't exist. Ignoring...", sectorNumber); 208 return; 209 } 210 211 this.Log(LogLevel.Noisy, "Erasing sector {0}, offset 0x{1:X}, size 0x{2:X}", sectorNumber, Sectors[sectorNumber].Offset, Sectors[sectorNumber].Size); 212 flash.WriteBytes(Sectors[sectorNumber].Offset, ErasePattern, Sectors[sectorNumber].Size); 213 } 214 PerformMassErase()215 private void PerformMassErase() 216 { 217 this.Log(LogLevel.Noisy, "Performing flash mass erase"); 218 foreach(var sectorNumber in Sectors.Keys) 219 { 220 PerformSectorErase(sectorNumber); 221 } 222 } 223 224 private readonly MappedMemory flash; 225 private readonly LockRegister controlLock; 226 private readonly LockRegister optionControlLock; 227 private readonly DoubleWordRegisterCollection optionBytesRegisters; 228 229 private IValueRegisterField readProtectionRegister; 230 private IValueRegisterField writeProtectionRegister; 231 232 private IValueRegisterField readProtectionOptionBytes; 233 private IValueRegisterField writeProtectionOptionBytes; 234 235 private static readonly uint[] ControlLockKey = {0x45670123, 0xCDEF89AB}; 236 private static readonly uint[] OptionLockKey = {0x8192A3B, 0x4C5D6E7F}; 237 private static readonly byte[] ErasePattern = Enumerable.Repeat((byte)0xFF, MaxSectorSize).ToArray(); 238 private static readonly Dictionary<uint, Sector> Sectors = new Dictionary<uint, Sector>() 239 { 240 { 0, new Sector { Offset = 0x00000000, Size = 0x4000 } }, 241 { 1, new Sector { Offset = 0x00004000, Size = 0x4000 } }, 242 { 2, new Sector { Offset = 0x00008000, Size = 0x4000 } }, 243 { 3, new Sector { Offset = 0x0000C000, Size = 0x4000 } }, 244 { 4, new Sector { Offset = 0x00010000, Size = 0x4000 } }, 245 { 5, new Sector { Offset = 0x00020000, Size = 0x10000 } }, 246 { 6, new Sector { Offset = 0x00040000, Size = 0x20000 } }, 247 { 7, new Sector { Offset = 0x00060000, Size = 0x20000 } }, 248 { 8, new Sector { Offset = 0x00080000, Size = 0x20000 } }, 249 { 9, new Sector { Offset = 0x000A0000, Size = 0x20000 } }, 250 { 10, new Sector { Offset = 0x000C0000, Size = 0x20000 } }, 251 { 11, new Sector { Offset = 0x000E0000, Size = 0x20000 } }, 252 }; 253 254 private const int MaxSectorSize = 0x20000; 255 256 private class Sector 257 { 258 public uint Offset { get; set; } 259 public int Size { get; set; } 260 } 261 262 private enum Registers 263 { 264 AccessControl = 0x00, // FLASH_ACR 265 Key = 0x04, // FLASH_KEYR 266 OptionKey = 0x08, // FLASH_OPTKEYR 267 Status = 0x0C, // FLASH_SR 268 Control = 0x10, // FLASH_CR 269 OptionControl = 0x14, // FLASH_OPTCR 270 } 271 272 private enum OptionBytesRegisters 273 { 274 ReadProtectionAndUser = 0x0, 275 WriteProtection = 0x8, 276 } 277 } 278 } 279