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