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