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 8 using System; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Peripherals.Bus; 15 16 namespace Antmicro.Renode.Peripherals.Miscellaneous 17 { 18 public class MPFS_Sysreg : IDoubleWordPeripheral, IKnownSize 19 { MPFS_Sysreg(IMachine machine)20 public MPFS_Sysreg(IMachine machine) 21 { 22 sysbus = machine.GetSystemBus(this); 23 24 peripheralMap = new PeripheralDisableInfo[] 25 { 26 new PeripheralDisableInfo { Address = 0x20200000, Name = "ENVM" }, 27 new PeripheralDisableInfo { Address = 0x20110000, Name = "MAC0" }, 28 new PeripheralDisableInfo { Address = 0x20112000, Name = "MAC1" }, 29 new PeripheralDisableInfo { Address = 0x20008000, Name = "MMC" }, 30 new PeripheralDisableInfo { Address = 0x20125000, Name = "TIMER" }, 31 new PeripheralDisableInfo { Address = 0x20000000, Name = "MMUART0" }, 32 new PeripheralDisableInfo { Address = 0x20100000, Name = "MMUART1" }, 33 new PeripheralDisableInfo { Address = 0x20102000, Name = "MMUART2" }, 34 new PeripheralDisableInfo { Address = 0x20104000, Name = "MMUART3" }, 35 new PeripheralDisableInfo { Address = 0x20106000, Name = "MMUART4" }, 36 new PeripheralDisableInfo { Address = 0x20108000, Name = "SPI0" }, 37 new PeripheralDisableInfo { Address = 0x20109000, Name = "SPI1" }, 38 new PeripheralDisableInfo { Address = 0x2010A000, Name = "I2C0" }, 39 new PeripheralDisableInfo { Address = 0x2010B000, Name = "I2C1" }, 40 new PeripheralDisableInfo { Address = 0x2010C000, Name = "CAN0" }, 41 new PeripheralDisableInfo { Address = 0x2010D000, Name = "CAN1" }, 42 new PeripheralDisableInfo { Address = 0x20201000, Name = "USB" }, 43 new PeripheralDisableInfo { Address = null, Name = "FPGA" }, 44 new PeripheralDisableInfo { Address = 0x20124000, Name = "MSRTC" }, 45 new PeripheralDisableInfo { Address = 0x21000000, Name = "QSPI" }, 46 new PeripheralDisableInfo { Address = 0x20120000, Name = "GPIO0" }, 47 new PeripheralDisableInfo { Address = 0x20121000, Name = "GPIO1" }, 48 new PeripheralDisableInfo { Address = 0x20122000, Name = "GPIO2" }, 49 new PeripheralDisableInfo { Address = 0x20080000, Name = "DDRC" }, 50 new PeripheralDisableInfo { Address = null, Name = "FIC0" }, 51 new PeripheralDisableInfo { Address = null, Name = "FIC1" }, 52 new PeripheralDisableInfo { Address = null, Name = "FIC2" }, 53 new PeripheralDisableInfo { Address = null, Name = "FIC3" }, 54 new PeripheralDisableInfo { Address = 0x22000000, Name = "ATHENA" }, 55 new PeripheralDisableInfo { Address = null, Name = "CFM" }, 56 new PeripheralDisableInfo { Address = null, Name = "SGMII" }, 57 }; 58 59 var registersMap = new Dictionary<long, DoubleWordRegister> 60 { 61 // Enables the clock to the MSS peripheral. When the clock is off the peripheral should not be accessed. 62 {(long)Registers.SubblkClockCr, new DoubleWordRegister(this) 63 .WithFlag(0, writeCallback: (_, val) => ManageClock(val, 0), name: "ENVM") 64 .WithFlag(1, writeCallback: (_, val) => ManageClock(val, 1), name: "MAC0") 65 .WithFlag(2, writeCallback: (_, val) => ManageClock(val, 2), name: "MAC1") 66 .WithFlag(3, writeCallback: (_, val) => ManageClock(val, 3), name: "MMC") 67 .WithFlag(4, writeCallback: (_, val) => ManageClock(val, 4), name: "TIMER") 68 .WithFlag(5, writeCallback: (_, val) => ManageClock(val, 5), name: "MMUART0") 69 .WithFlag(6, writeCallback: (_, val) => ManageClock(val, 6), name: "MMUART1") 70 .WithFlag(7, writeCallback: (_, val) => ManageClock(val, 7), name: "MMUART2") 71 .WithFlag(8, writeCallback: (_, val) => ManageClock(val, 8), name: "MMUART3") 72 .WithFlag(9, writeCallback: (_, val) => ManageClock(val, 9), name: "MMUART4") 73 .WithFlag(10, writeCallback: (_, val) => ManageClock(val, 10), name: "SPI0") 74 .WithFlag(11, writeCallback: (_, val) => ManageClock(val, 11), name: "SPI1") 75 .WithFlag(12, writeCallback: (_, val) => ManageClock(val, 12), name: "I2C0") 76 .WithFlag(13, writeCallback: (_, val) => ManageClock(val, 13), name: "I2C1") 77 .WithFlag(14, writeCallback: (_, val) => ManageClock(val, 14), name: "CAN0") 78 .WithFlag(15, writeCallback: (_, val) => ManageClock(val, 15), name: "CAN1") 79 .WithFlag(16, writeCallback: (_, val) => ManageClock(val, 16), name: "USB") 80 .WithTag("FPGA", 17, 1) 81 .WithFlag(18, writeCallback: (_, val) => ManageClock(val, 18), name: "MSRTC") 82 .WithFlag(19, writeCallback: (_, val) => ManageClock(val, 19), name: "QSPI") 83 .WithFlag(20, writeCallback: (_, val) => ManageClock(val, 20), name: "GPIO0") 84 .WithFlag(21, writeCallback: (_, val) => ManageClock(val, 21), name: "GPIO1") 85 .WithFlag(22, writeCallback: (_, val) => ManageClock(val, 22), name: "GPIO2") 86 .WithFlag(23, writeCallback: (_, val) => ManageClock(val, 23), name: "DDRC") 87 .WithTag("FIC0", 24, 1) 88 .WithTag("FIC1", 25, 1) 89 .WithTag("FIC2", 26, 1) 90 .WithTag("FIC3", 27, 1) 91 .WithFlag(28, writeCallback: (_, val) => ManageClock(val, 28), name: "ATHENA") 92 .WithTag("CFM", 29, 1) 93 .WithReservedBits(30, 1) 94 .WithReservedBits(31, 1) 95 }, 96 97 // Holds the MSS peripherals in reset. When in reset the peripheral should not be accessed. 98 {(long)Registers.SoftResetCr, new DoubleWordRegister(this, 0x7FFFFFFE) 99 .WithFlag(0, writeCallback: (_, val) => ManageSoftReset(val, 0), name: "ENVM") 100 .WithFlag(1, writeCallback: (_, val) => ManageSoftReset(val, 1), name: "MAC0") 101 .WithFlag(2, writeCallback: (_, val) => ManageSoftReset(val, 2), name: "MAC1") 102 .WithFlag(3, writeCallback: (_, val) => ManageSoftReset(val, 3), name: "MMC") 103 .WithFlag(4, writeCallback: (_, val) => ManageSoftReset(val, 4), name: "TIMER") 104 .WithFlag(5, writeCallback: (_, val) => ManageSoftReset(val, 5), name: "MMUART0") 105 .WithFlag(6, writeCallback: (_, val) => ManageSoftReset(val, 6), name: "MMUART1") 106 .WithFlag(7, writeCallback: (_, val) => ManageSoftReset(val, 7), name: "MMUART2") 107 .WithFlag(8, writeCallback: (_, val) => ManageSoftReset(val, 8), name: "MMUART3") 108 .WithFlag(9, writeCallback: (_, val) => ManageSoftReset(val, 9), name: "MMUART4") 109 .WithFlag(10, writeCallback: (_, val) => ManageSoftReset(val, 10), name: "SPI0") 110 .WithFlag(11, writeCallback: (_, val) => ManageSoftReset(val, 11), name: "SPI1") 111 .WithFlag(12, writeCallback: (_, val) => ManageSoftReset(val, 12), name: "I2C0") 112 .WithFlag(13, writeCallback: (_, val) => ManageSoftReset(val, 13), name: "I2C1") 113 .WithFlag(14, writeCallback: (_, val) => ManageSoftReset(val, 14), name: "CAN0") 114 .WithFlag(15, writeCallback: (_, val) => ManageSoftReset(val, 15), name: "CAN1") 115 .WithFlag(16, writeCallback: (_, val) => ManageSoftReset(val, 16), name: "USB") 116 .WithTag("FPGA", 17, 1) 117 .WithFlag(18, writeCallback: (_, val) => ManageSoftReset(val, 18), name: "MSRTC") 118 .WithFlag(19, writeCallback: (_, val) => ManageSoftReset(val, 19), name: "QSPI") 119 .WithFlag(20, writeCallback: (_, val) => ManageSoftReset(val, 20), name: "GPIO0") 120 .WithFlag(21, writeCallback: (_, val) => ManageSoftReset(val, 21), name: "GPIO1") 121 .WithFlag(22, writeCallback: (_, val) => ManageSoftReset(val, 22), name: "GPIO2") 122 .WithFlag(23, writeCallback: (_, val) => ManageSoftReset(val, 23), name: "DDRC") 123 .WithTag("FIC0", 24, 1) 124 .WithTag("FIC1", 25, 1) 125 .WithTag("FIC2", 26, 1) 126 .WithTag("FIC3", 27, 1) 127 .WithFlag(28, writeCallback: (_, val) => ManageSoftReset(val, 28), name: "ATHENA") 128 .WithTag("CFM", 29, 1) 129 .WithTag("SGMII", 30, 1) 130 .WithReservedBits(31, 1) 131 }, 132 {(long)Registers.ClockConfigCr, new DoubleWordRegister(this, 0x10) 133 .WithTag("ClockConfig", 0, 32) 134 }, 135 {(long)Registers.EnvmCr, new DoubleWordRegister(this, 0xFF) 136 .WithTag("Envm", 0, 32) 137 }, 138 {(long)Registers.RtcClockCr, new DoubleWordRegister(this, 0x1064) 139 .WithTag("RtcClock", 0, 32) 140 }, 141 {(long)Registers.PllStatusSr, new DoubleWordRegister(this, 0x707) 142 .WithTag("PllStatus", 0, 32) 143 }, 144 {(long)Registers.EdacSr, new DoubleWordRegister(this) 145 .WithTag("Edac", 0, 32) 146 }, 147 {(long)Registers.EdacIntenCr, new DoubleWordRegister(this) 148 .WithTag("EdacInten", 0, 32) 149 }, 150 {(long)Registers.EdacCntMmc, new DoubleWordRegister(this) 151 .WithTag("EdacCntMmc", 0, 32) 152 }, 153 {(long)Registers.EdacCntDdrc, new DoubleWordRegister(this) 154 .WithTag("EdacCntDrdc", 0, 32) 155 }, 156 {(long)Registers.EdacCntMac0, new DoubleWordRegister(this) 157 .WithTag("EdacCntMac0", 0, 32) 158 }, 159 {(long)Registers.EdacCntMac1, new DoubleWordRegister(this) 160 .WithTag("EdacCntMac1", 0, 32) 161 }, 162 {(long)Registers.EdacCntUsb, new DoubleWordRegister(this) 163 .WithTag("EdacCntUsb", 0, 32) 164 }, 165 {(long)Registers.EdacCntCan0, new DoubleWordRegister(this) 166 .WithTag("EdacCntCan0", 0, 32) 167 }, 168 {(long)Registers.EdacCntCan1, new DoubleWordRegister(this) 169 .WithTag("EdacCntCan1", 0, 32) 170 }, 171 {(long)Registers.MaintenanceIntSr, new DoubleWordRegister(this) 172 .WithTag("MaintenanceInt", 0, 32) 173 }, 174 {(long)Registers.MiscSr, new DoubleWordRegister(this) 175 .WithTag("Misc", 0, 32) 176 }, 177 {(long)Registers.DLLStatusSr, new DoubleWordRegister(this) 178 .WithTag("DLLStatus", 0, 32) 179 }, 180 {(long)Registers.BootFailC, new DoubleWordRegister(this) 181 .WithTag("BootFail", 0, 32) 182 }, 183 {(long)Registers.DeviceStatus, new DoubleWordRegister(this, 0x1F09) 184 .WithTag("Devicestatus", 0, 32) 185 }, 186 {(long)Registers.MpuViolationSr, new DoubleWordRegister(this) 187 .WithTag("MpuViolation", 0, 32) 188 }, 189 }; 190 registers = new DoubleWordRegisterCollection(this, registersMap); 191 } 192 ReadDoubleWord(long offset)193 public uint ReadDoubleWord(long offset) 194 { 195 return registers.Read(offset); 196 } 197 WriteDoubleWord(long offset, uint value)198 public void WriteDoubleWord(long offset, uint value) 199 { 200 registers.Write(offset, value); 201 } 202 Reset()203 public void Reset() 204 { 205 registers.Reset(); 206 } 207 208 public long Size => 0x1000; 209 ManageClock(bool val, int index)210 private void ManageClock(bool val, int index) 211 { 212 var info = peripheralMap[index]; 213 if(val) 214 { 215 info.Type &= ~(DisableType.Clock); 216 } 217 else 218 { 219 info.Type |= DisableType.Clock; 220 } 221 ManagePeripheral(info); 222 } 223 ManageSoftReset(bool val, int index)224 private void ManageSoftReset(bool val, int index) 225 { 226 var info = peripheralMap[index]; 227 if(val) 228 { 229 info.Type |= DisableType.SoftReset; 230 } 231 else 232 { 233 info.Type &= ~(DisableType.SoftReset); 234 } 235 ManagePeripheral(info); 236 } 237 ManagePeripheral(PeripheralDisableInfo info)238 private void ManagePeripheral(PeripheralDisableInfo info) 239 { 240 if(!info.Address.HasValue) 241 { 242 this.Log(LogLevel.Warning, "Cannot manage peripheral {0} because of invalid address.", info.Name); 243 return; 244 } 245 var peripheral = sysbus.WhatPeripheralIsAt(info.Address.Value); 246 if(peripheral == null) 247 { 248 this.Log(LogLevel.Warning, "Cannot manage peripheral {0} because it is not registered.", info.Name); 249 return; 250 } 251 if((info.Type & DisableType.Clock) == 0) 252 { 253 this.Log(LogLevel.Debug, "Enabling peripheral {0}.", info.Name); 254 sysbus.EnablePeripheral(peripheral); 255 } 256 else 257 { 258 this.Log(LogLevel.Debug, "Disabling peripheral {0}.", info.Name); 259 sysbus.DisablePeripheral(peripheral); 260 } 261 if((info.Type & DisableType.SoftReset) != 0) 262 { 263 this.Log(LogLevel.Debug, "Resetting peripheral {0}.", info.Name); 264 peripheral.Reset(); 265 } 266 } 267 268 private readonly DoubleWordRegisterCollection registers; 269 private readonly PeripheralDisableInfo[] peripheralMap; 270 private readonly IBusController sysbus; 271 272 private struct PeripheralDisableInfo 273 { 274 public ulong? Address; 275 public DisableType Type; 276 public string Name; 277 } 278 279 [Flags] 280 private enum DisableType 281 { 282 None = 0, 283 Clock = 0x1, 284 SoftReset = 0x2 285 } 286 287 private enum Registers 288 { 289 Temp0 = 0x0, 290 Temp1 = 0x4, 291 ClockConfigCr = 0x8, 292 RtcClockCr = 0xC, 293 FabricResetCr = 0x10, 294 BootFailC = 0x14, 295 MssLowPowerCr = 0x18, 296 ConfigLockCr = 0x1C, 297 ResetSr = 0x20, 298 DeviceStatus = 0x24, 299 FabIntenU541 = 0x40, 300 FabIntenU542 = 0x44, 301 FabIntenU543 = 0x48, 302 FabIntenU544 = 0x4C, 303 FabIntenMisc = 0x50, 304 GpioInterruptFabCr = 0x54, 305 ApbbusCr = 0x80, 306 SubblkClockCr = 0x84, 307 SoftResetCr = 0x88, 308 AhbaxiCr = 0x8C, 309 DfiapbCr = 0x98, 310 GpioCr = 0x9C, 311 Mac0Cr = 0xA4, 312 Mac1Cr = 0xA8, 313 UsbCr = 0xAC, 314 MeshCr = 0xB0, 315 MeshSeedCr = 0xB4, 316 EnvmCr = 0xB8, 317 ReservedBc = 0xBC, 318 QosPeripheralCr = 0xC0, 319 QosCplexioCr = 0xC4, 320 QosCplexddrCr = 0xC8, 321 MpuViolationSr = 0xF0, 322 MpuViolationIntenCr = 0xF4, 323 SwFailAddr0Cr = 0xF8, 324 SwFailAddr1Cr = 0xFC, 325 EdacSr = 0x100, 326 EdacIntenCr = 0x104, 327 EdacCntMmc = 0x108, 328 EdacCntDdrc = 0x10C, 329 EdacCntMac0 = 0x110, 330 EdacCntMac1 = 0x114, 331 EdacCntUsb = 0x118, 332 EdacCntCan0 = 0x11C, 333 EdacCntCan1 = 0x120, 334 EdacInjectCr = 0x124, 335 MaintenanceIntenCr = 0x140, 336 PllStatusIntenCr = 0x144, 337 MaintenanceIntSr = 0x148, 338 PllStatusSr = 0x14C, 339 CfmTimerCr = 0x150, 340 MiscSr = 0x154, 341 DLLStatusSr = 0x15C, 342 RamLightsleepCr = 0x168, 343 RamDeepsleepCr = 0x16C, 344 RamShutdownCr = 0x170, 345 Iomux0Cr = 0x200, 346 Iomux1Cr = 0x204, 347 Iomux2Cr = 0x208, 348 Iomux3Cr = 0x20C, 349 Iomux4Cr = 0x210, 350 Iomux5Cr = 0x214, 351 Iomux6Cr = 0x218, 352 MssioBank4CfgCr = 0x230, 353 MssioBank4IoCfg0Cr = 0x234, 354 MssioBank4IoCfg1Cr = 0x238, 355 MssioBank4IoCfg2Cr = 0x23C, 356 MssioBank4IoCfg3Cr = 0x240, 357 MssioBank4IoCfg4Cr = 0x244, 358 MssioBank4IoCfg5Cr = 0x248, 359 MssioBank4IoCfg6Cr = 0x24C, 360 MssioBank2CfgCr = 0x250, 361 MssioBank2IoCfg0Cr = 0x254, 362 MssioBank2IoCfg1Cr = 0x258, 363 MssioBank2IoCfg2Cr = 0x25C, 364 MssioBank2IoCfg3Cr = 0x260, 365 MssioBank2IoCfg4Cr = 0x264, 366 MssioBank2IoCfg5Cr = 0x268, 367 MssioBank2IoCfg6Cr = 0x26C, 368 MssioBank2IoCfg7Cr = 0x270, 369 MssioBank2IoCfg8Cr = 0x274, 370 MssioBank2IoCfg9Cr = 0x278, 371 MssioBank2IoCfg10Cr = 0x27C, 372 MssioBank2IoCfg11Cr = 0x280, 373 MssSpare0Cr = 0x2A8, 374 MssSpare1Cr = 0x2AC, 375 MssSpare0Sr = 0x2B0, 376 MssSpare1Sr = 0x2B4, 377 MssSpare2Sr = 0x2B8, 378 MssSpare3Sr = 0x2BC, 379 MssSpare4Sr = 0x2C0, 380 MssSpare5Sr = 0x2C4, 381 SpareRegisterRw = 0x2D0, 382 SpareRegisterW1p = 0x2D4, 383 SpareRegisterRo = 0x2D8, 384 SparePerimRw = 0x2DC 385 } 386 } 387 } 388