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