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 
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Peripherals.Sensor;
14 
15 namespace Antmicro.Renode.Peripherals.Sensors
16 {
17     public class PULP_uDMA_Camera: NullRegistrationPointPeripheralContainer<ICPIPeripheral>, IDoubleWordPeripheral, IKnownSize, IProvidesRegisterCollection<DoubleWordRegisterCollection>
18     {
PULP_uDMA_Camera(IMachine machine)19         public PULP_uDMA_Camera(IMachine machine) : base(machine)
20         {
21             IRQ = new GPIO();
22             sysbus = machine.GetSystemBus(this);
23 
24             RegistersCollection = new DoubleWordRegisterCollection(this);
25             DefineRegisters();
26         }
27 
Reset()28         public override void Reset()
29         {
30             RegistersCollection.Reset();
31             // there is no need to clear IRQ
32             // as we only blink with it
33         }
34 
ReadDoubleWord(long offset)35         public uint ReadDoubleWord(long offset)
36         {
37             return RegistersCollection.Read(offset);
38         }
39 
WriteDoubleWord(long offset, uint value)40         public void WriteDoubleWord(long offset, uint value)
41         {
42             RegistersCollection.Write(offset, value);
43         }
44 
45         public DoubleWordRegisterCollection RegistersCollection { get; }
46 
47         public GPIO IRQ { get; }
48 
49         public long Size => 0x100;
50 
DefineRegisters()51         private void DefineRegisters()
52         {
53             Registers.RxBufferBaseAddress.Define(this)
54                 // this is not consistent with the documentation
55                 // that states that only 16 bits are used for the address,
56                 // but otherwise the sample fails
57                 .WithValueField(0, 32, out rxBufferAddress, name: "RX_SADDR")
58             ;
59 
60             Registers.RxBufferSize.Define(this)
61                 .WithValueField(0, 17, out rxBufferSize, name: "RX_SIZE")
62                 .WithReservedBits(17, 15)
63             ;
64 
65             Registers.RxStreamConfiguration.Define(this)
66                 .WithTag("CONTINOUS", 0, 1)
67                 .WithTag("DATASIZE", 1, 2)
68                 .WithReservedBits(3, 1)
69                 .WithFlag(4, out rxStreamEnabled, name: "EN")
70                 .WithTag("PENDING", 5, 1)
71                 .WithTag("CLR", 6, 1)
72                 .WithReservedBits(7, 25)
73             ;
74 
75             Registers.GlobalConfiguration.Define(this)
76                 .WithTag("FRAMEDROP_EN", 0, 1)
77                 .WithTag("FRAMEDROP_VAL", 1, 6)
78                 .WithTag("FRAMESLICE_EN", 7, 1)
79                 .WithTag("FORMAT", 8, 3)
80                 .WithTag("SHIFT", 11, 4)
81                 .WithReservedBits(15, 16)
82                 .WithFlag(31, FieldMode.Read | FieldMode.WriteOneToClear, name: "EN", writeCallback: (_, val) =>
83                 {
84                     // write-one-to-clear means that this bit is automatically
85                     // cleared after writing
86 
87                     if(!val)
88                     {
89                         return;
90                     }
91 
92                     if(!rxStreamEnabled.Value)
93                     {
94                         this.Log(LogLevel.Warning, "Tried to enable the controller, but RX DMA stream is not enabled. Dropping it");
95                         return;
96                     }
97 
98                     if(RegisteredPeripheral == null)
99                     {
100                         this.Log(LogLevel.Warning, "Tried to enable the controller, but there is no device connected");
101                         return;
102                     }
103 
104                     var data = RegisteredPeripheral.ReadFrame();
105 
106                     if(data.Length != (int)rxBufferSize.Value)
107                     {
108                         this.Log(LogLevel.Warning, "Received {0} bytes from the device, but RX DMA stream is configured for {1} bytes. This might indicate problems in the driver", data.Length, rxBufferSize.Value);
109                     }
110 
111                     sysbus.WriteBytes(data, rxBufferAddress.Value);
112                     rxStreamEnabled.Value = false;
113                     IRQ.Blink();
114                 })
115             ;
116 
117             Registers.LowerLeftCornerConfiguration.Define(this)
118                 .WithTag("FRAMESLICE_LLX", 0, 16)
119                 .WithTag("FRAMESLICE_LLY", 16, 16)
120             ;
121 
122             Registers.UpperRightCornderConfiguration.Define(this)
123                 .WithTag("FRAMESLICE_URX", 0, 16)
124                 .WithTag("FRAMESLICE_URY", 16, 16)
125             ;
126 
127             Registers.HorizontalResolutionConfiguration.Define(this)
128                 .WithReservedBits(0, 16)
129                 .WithTag("ROWLEN", 16, 16)
130             ;
131 
132             Registers.RGBCoefficientsConfiguration.Define(this)
133                 .WithTag("B_COEFF", 0, 8)
134                 .WithTag("G_COEFF", 8, 8)
135                 .WithTag("R_COEFF", 16, 8)
136                 .WithReservedBits(24, 8)
137             ;
138 
139             Registers.VSYNCPolarity.Define(this)
140                 .WithTag("VSYNC_POLARITY", 0, 1)
141                 .WithReservedBits(1, 31)
142             ;
143         }
144 
145         private IValueRegisterField rxBufferAddress;
146         private IValueRegisterField rxBufferSize;
147         private IFlagRegisterField rxStreamEnabled;
148 
149         private readonly IBusController sysbus;
150 
151         private enum Registers
152         {
153             RxBufferBaseAddress = 0x0,
154             RxBufferSize = 0x4,
155             RxStreamConfiguration = 0x8,
156 
157             GlobalConfiguration = 0x20,
158             LowerLeftCornerConfiguration = 0x24,
159             UpperRightCornderConfiguration = 0x28,
160             HorizontalResolutionConfiguration = 0x2C,
161             RGBCoefficientsConfiguration = 0x30,
162             VSYNCPolarity = 0x34
163         }
164     }
165 }
166