1 //
2 // Copyright (c) 2010-2018 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using Antmicro.Renode.Peripherals.Bus;
8 using Antmicro.Renode.Logging;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using System.Collections.Generic;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Peripherals.Timers;
13 
14 namespace Antmicro.Renode.Peripherals
15 {
16     public class STM32L_RTC : LimitTimer, IDoubleWordPeripheral
17     {
STM32L_RTC(IMachine machine)18         public STM32L_RTC(IMachine machine) : base(machine.ClockSource, 1000, eventEnabled: true, autoUpdate: true) // this frequency is a blind guess
19         {
20             IRQ = new GPIO();
21             LimitReached += () =>
22             {
23                 if(wakeupTimerInterruptEnable.Value)
24                 {
25                     wakeupTimerFlag.Value = true;
26                     this.DebugLog("Setting IRQ");
27                     IRQ.Set();
28                 }
29             };
30             SetupRegisters();
31         }
32 
Reset()33         public override void Reset()
34         {
35             base.Reset();
36             registers.Reset();
37             IRQ.Unset();
38         }
39 
ReadDoubleWord(long offset)40         public uint ReadDoubleWord(long offset)
41         {
42             return registers.Read(offset);
43         }
44 
WriteDoubleWord(long offset, uint value)45         public void WriteDoubleWord(long offset, uint value)
46         {
47             registers.Write(offset, value);
48         }
49 
50         public GPIO IRQ { get; private set; }
51 
SetupRegisters()52         private void SetupRegisters()
53         {
54             var control = new DoubleWordRegister(this)
55                 .WithEnumField<DoubleWordRegister, ClockMode>(0, 3, name: "WUCKSEL", writeCallback: (_, value) =>
56             {
57                 this.DebugLog("Setting wucksel to {0}", value);
58                 // for now we ignore changing clock frequency
59             })
60                 .WithFlag(10, name: "WUTE", writeCallback: (_, value) =>
61             {
62                 this.DebugLog(value ? "Enabling timer" : "Disabling timer");
63                 Enabled = value;
64             });
65             wakeupTimerInterruptEnable = control.DefineFlagField(14, name: "WUTIE");
66 
67             var initializationStatus = new DoubleWordRegister(this, 0x7);
68             wakeupTimerFlag = initializationStatus.DefineFlagField(10, FieldMode.Read | FieldMode.WriteZeroToClear, name: "WUTF", writeCallback: (_, value) =>
69             {
70                 if(!value)
71                 {
72                     this.DebugLog("Clearing IRQ");
73                     IRQ.Unset();
74                 }
75             });
76 
77             var wakeupTimer = new DoubleWordRegister(this).WithValueField(0, 16, name: "WUT", writeCallback: (_, value) =>
78             {
79                 this.DebugLog("Setting limit to {0}", value);
80                 Limit = value;
81             });
82 
83             var registerDictionary = new Dictionary<long, DoubleWordRegister> {
84                 { (long)Registers.Control, control },
85                 { (long)Registers.InitializationStatus, initializationStatus },
86                 { (long)Registers.WakeupTimer, wakeupTimer }
87             };
88             registers = new DoubleWordRegisterCollection(this, registerDictionary);
89         }
90 
91         private enum ClockMode
92         {
93             RTC_16,
94             RTC_8,
95             RTC_4,
96             RTC_2,
97             CK_SPRE1,
98             CK_SPRE2,
99             CK_SPRE3,
100             CK_SPRE4
101         }
102 
103         private enum Registers
104         {
105             Control = 0x8,
106             InitializationStatus = 0xC,
107             WakeupTimer = 0x14
108         }
109 
110         private DoubleWordRegisterCollection registers;
111         private IFlagRegisterField wakeupTimerFlag;
112         private IFlagRegisterField wakeupTimerInterruptEnable;
113     }
114 }
115 
116