1 //
2 // Copyright (c) 2010-2023 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.Bus;
12 
13 namespace Antmicro.Renode.Peripherals.DMA
14 {
15     public sealed class TegraDmaHost1X : IDoubleWordPeripheral, IKnownSize
16     {
TegraDmaHost1X(IMachine machine)17         public TegraDmaHost1X(IMachine machine)
18         {
19             dmaEngine = new DmaEngine(machine.GetSystemBus(this));
20             sysbus = machine.GetSystemBus(this);
21         }
22 
23         public long Size
24         {
25             get
26             {
27                 return 0x100;
28             }
29         }
30 
ReadDoubleWord(long offset)31         public uint ReadDoubleWord(long offset)
32         {
33             this.LogUnhandledRead(offset);
34             return 0;
35         }
36 
37 	public uint classid = 0xFFFFFFFF;
38 
Execute_DMA(ulong offset)39 	public uint Execute_DMA(ulong offset) {
40 		uint result = 4;
41 		uint vl = sysbus.ReadDoubleWord(offset);
42 		var opcode = ((vl >> 28) & 0xF);
43 		uint count, addr;
44 		switch (opcode) {
45 			case 0x0:
46 				classid =  ((vl >> 6) & 0x3FF);
47 				this.Log(LogLevel.Warning, "Opcode 0x0 SETCL, set to 0x{0:X}",classid);
48 				break;
49 			case 0x1:
50 				count = vl & 0xFFFF;
51 				addr = ((vl >> 16) & 0xFFF) * 4;
52 				this.Log(LogLevel.Warning, "Opcode 0x1 INCR, wcount = {0}", count);
53  				if (classid == 0x30) {
54                                 	// VIP module
55                                         this.DebugLog("Write to VI @ 0x{0:X} count {1} bytes, first_val = {2:X}", 0x54080000 + addr, count*4, sysbus.ReadDoubleWord(offset + 4));
56                                         dmaEngine.IssueCopy(new Request(offset + 4, 0x54080000 + addr, (int)(count*4), TransferType.DoubleWord, TransferType.DoubleWord));
57                                 } else if (classid == 0x01) {
58                                         this.DebugLog("class nvhost 0x01 - syncpt control. next_val = {0:X} at addr {1:X}. not implemented yet.", sysbus.ReadDoubleWord(offset+4),addr);
59                                 } else {
60                                         this.DebugLog("classid = {0:X} not recognized!", classid);
61 				}
62 				result += count * 4;
63 				break;
64 			case 0x6:
65 				count = vl & 0x3FFF;
66 				this.Log(LogLevel.Warning, "Opcode 0x6 GATHER, count = {0}", count);
67 				/*
68 				this.Log(LogLevel.Warning, "Executing gather list >>> ");
69 				ptr = 0;
70 				while (ptr < (count*4)) ptr += Execute_DMA(offset + ptr);
71 				this.Log(LogLevel.Warning, "Executing list done <<< ");
72 				*/
73 				break;
74 			case 0x2:
75 				count = vl & 0xFFFF;
76 	                        this.Log(LogLevel.Warning, "Opcode 0x1 INCR, count = {0}", count);
77 	                        result += count * 4;
78 				break;
79 			default:
80 				this.Log(LogLevel.Warning, "Opcode 0x{0:X} UNSUPPORTED!", opcode);
81 				break;
82 		}
83 		return result;
84 	}
85 
86 
WriteDoubleWord(long offset, uint value)87         public void WriteDoubleWord(long offset, uint value)
88         {
89             if((Register)offset == Register.HOST1X_CHANNEL_DMAPUT)
90             {
91                 //this.DebugLog("We will have a command at addr 0x{0:X}", value & 0xFFFFFFFC);
92                 if(this.command_addr == 0x0)
93                 {
94                     this.command_addr = (value >> 2) * 4;
95                     return;
96                 }
97 /*      } else if ((Register)offset == Register.HOST1X_CHANNEL_DMACTRL) {
98             if (value == 0x7) {*/
99 		uint opc = (sysbus.ReadDoubleWord(this.command_addr) >>  28) & 0xF;
100 		Execute_DMA(this.command_addr);
101 		if (opc == 6) {
102 			// gather
103                 	uint cmd_l = 4 * (sysbus.ReadDoubleWord(this.command_addr) & 0x3FFF);
104 	                uint cmd_ad = (sysbus.ReadDoubleWord(this.command_addr + 4) >> 2) * 4;
105 			uint ptr = 0;
106 			this.Log(LogLevel.Warning, ">>> Executing gather list of size {0} >>> ", cmd_l);
107 			while (ptr < cmd_l) {
108 				ptr = ptr + Execute_DMA(cmd_ad + ptr);
109 			}
110 			this.Log(LogLevel.Warning, "<<< Executing list done <<< ");
111 		}
112 
113 /*
114                 uint cmd_len = sysbus.ReadDoubleWord(this.command_addr) & 0x3FFF;
115 		uint op = (sysbus.ReadDoubleWord(this.command_addr) >>  28) & 0xF;
116                 uint cmd_addr = (sysbus.ReadDoubleWord(this.command_addr + 4) >> 2) * 4;
117                 this.Log(LogLevel.Warning, "Command buffer is at < 0x{0:X} .. 0x{3:X} >, len={1}, opcode={2:X}", cmd_addr, cmd_len,op,cmd_addr+cmd_len*4-1);
118 		if (op != 0x6) {
119 		 this.Log(LogLevel.Warning, "Weird. opcode should be GATHER (0x6). is = 0x{0:X}. Ommiting. Whole was {1:X}", op, sysbus.ReadDoubleWord(this.command_addr));
120 		 //TODO: this is probably an direct command. modify this so that it is supported. idea: read whole buf and send to additional method.
121 		 return;
122 		}
123                 int i = 0;
124                 while(i < cmd_len)
125                 {
126                     var vl = sysbus.ReadDoubleWord(cmd_addr + (i * 4));
127 		     this.Log(LogLevel.Warning, "{0:X} = {1:X}", cmd_addr+(i*4), vl);
128 
129                     i++;
130                     var count = (int)(vl & 0xFFFF);
131                     var addr = ((vl >> 16) & 0xFFF) * 4;
132                     var opcode = ((vl >> 28) & 0xF);
133 */
134 
135 /*
136 #define HCFCMD_OPCODE_SETCL                     _MK_ENUM_CONST(0)
137 #define HCFCMD_OPCODE_INCR                      _MK_ENUM_CONST(1)
138 #define HCFCMD_OPCODE_NONINCR                   _MK_ENUM_CONST(2)
139 #define HCFCMD_OPCODE_MASK                      _MK_ENUM_CONST(3)
140 #define HCFCMD_OPCODE_IMM                       _MK_ENUM_CONST(4)
141 #define HCFCMD_OPCODE_RESTART                   _MK_ENUM_CONST(5)
142 #define HCFCMD_OPCODE_GATHER                    _MK_ENUM_CONST(6)
143 #define HCFCMD_OPCODE_EXTEND                    _MK_ENUM_CONST(14)
144 #define HCFCMD_OPCODE_CHDONE                    _MK_ENUM_CONST(15)
145 
146 */
147 
148   //                  if(opcode == 0x1)
149     //                {
150 
151 /*
152 
153 #define NV_HOST1X_CLASS_ID                      0x01
154 
155 #define NV_VIDEO_ENCODE_MPEG_CLASS_ID           0x20
156 
157 #define NV_VIDEO_STREAMING_VI_CLASS_ID          0x30
158 #define NV_VIDEO_STREAMING_EPP_CLASS_ID         0x31
159 #define NV_VIDEO_STREAMING_ISP_CLASS_ID         0x32
160 #define NV_VIDEO_STREAMING_VCI_CLASS_ID         0x33
161 
162 #define NV_GRAPHICS_2D_DOWNLOAD_CLASS_ID        0x50
163 #define NV_GRAPHICS_2D_CLASS_ID                 0x51
164 #define NV_GRAPHICS_2D_SB_CLASS_ID              0x52
165 #define NV_GRAPHICS_2D_DOWNLOAD_CTX1_CLASS_ID   0x54
166 #define NV_GRAPHICS_2D_CTX1_CLASS_ID            0x55
167 #define NV_GRAPHICS_2D_SB_CTX1_CLASS_ID         0x56
168 #define NV_GRAPHICS_2D_DOWNLOAD_CTX2_CLASS_ID   0x58
169 #define NV_GRAPHICS_2D_SB_CTX2_CLASS_ID         0x5A
170 
171 #define NV_GRAPHICS_VS_CLASS_ID                 0x5C
172 
173 #define NV_GRAPHICS_3D_CLASS_ID                 0x60
174 
175 #define NV_DISPLAY_CLASS_ID                     0x70
176 #define NV_DISPLAYB_CLASS_ID                    0x71
177 #define NV_HDMI_CLASS_ID                        0x77
178 #define NV_DISPLAY_TVO_CLASS_ID                 0x78
179 #define NV_DISPLAY_DSI_CLASS_ID                 0x79
180 
181 #define NV_GRAPHICS_VG_CLASS_ID                 0xD0
182 
183 
184  */
185 /*
186 		    	if (classid == 0x30) {
187 	                        // VIP module
188 				this.DebugLog("Write to VI at {0:X} count {1}, first_val = {2:X}", 0x54080000 + addr, count*4, sysbus.ReadDoubleWord(cmd_addr+i*4));
189         	                dmaEngine.IssueCopy(new Request(cmd_addr + i * 4, 0x54080000 + addr, count*4, TransferType.DoubleWord, TransferType.DoubleWord));
190 			} else if (classid == 0x01) {
191 				this.DebugLog("class nvhost 0x01 - syncpt control. next_val = {0:X} at addr {1:X}. not implemented yet.", sysbus.ReadDoubleWord(cmd_addr+i*4),addr);
192 			} else {
193 				this.DebugLog("classid = {0:X} not recognized!", classid);
194 			}
195 			i += count;
196                     } else if (opcode == 0x2) {
197 		    	this.DebugLog("Opcode 0x02 NONINCR - not implemented. was {0} bytes.", count);
198 		    	i += count;
199 		    }
200                     else if (opcode == 0x0) {
201 		    	this.DebugLog("Opcode 0x00 SETCL --> class {0} set.", ((vl >> 6) & 0x3FF));
202 			classid = ((vl >> 6) & 0x3FF);
203 		    } else
204                     {
205                         this.DebugLog("opcode 0x{0:X} not recognized. [Data size was {1}, vl={2:X}]", opcode, count,vl);
206                     }
207                 }
208                 this.command_addr = value & 0xFFFFFFFC;
209 
210 //          }*/
211             }
212             else
213             {
214                 this.LogUnhandledWrite(offset, value);
215 
216             }
217         }
218 
Reset()219         public void Reset()
220         {
221             command_addr = 0;
222             classid = 0xFFFFFFFF;
223         }
224 
225         private enum Register
226         {
227             HOST1X_CHANNEL_DMASTART = 0x14,
228             HOST1X_CHANNEL_DMAPUT = 0x18,
229             HOST1X_CHANNEL_DMAEND = 0x20,
230             HOST1X_CHANNEL_DMACTRL = 0x24,
231         }
232 
233         private uint command_addr = 0x0;
234         private readonly DmaEngine dmaEngine;
235         private readonly IBusController sysbus;
236 
237     }
238 }
239 
240