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 using System;
8 using System.Collections.Generic;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Utilities;
15 
16 namespace Antmicro.Renode.Peripherals.SPI
17 {
18     [AllowedTranslations(AllowedTranslation.DoubleWordToByte)]
19     public class NPCX_FIU : NullRegistrationPointPeripheralContainer<ISPIPeripheral>, IBytePeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, IKnownSize
20     {
NPCX_FIU(IMachine machine)21         public NPCX_FIU(IMachine machine) : base(machine)
22         {
23             RegistersCollection = new ByteRegisterCollection(this);
24             DefineRegisters();
25             Reset();
26         }
27 
Reset()28         public override void Reset()
29         {
30             userModeAccessLocked = false;
31             userModeAccessAddress = 0x0;
32             userModeAccessData = 0x0;
33             use4ByteAddress = false;
34         }
35 
ReadByte(long offset)36         public byte ReadByte(long offset)
37         {
38             return RegistersCollection.Read(offset);
39         }
40 
WriteByte(long offset, byte value)41         public void WriteByte(long offset, byte value)
42         {
43             RegistersCollection.Write(offset, value);
44         }
45 
46         public long Size => 0x1000;
47         public ByteRegisterCollection RegistersCollection { get; }
48 
DefineRegisters()49         private void DefineRegisters()
50         {
51             Registers.UMACodeByte.Define(this)
52                 .WithValueField(0, 8, out userModeAccessCode, name: "TR_CODE (Transaction Code)");
53 
54             Registers.UMAAddressByte0_0.DefineMany(this, 3, (register, i) =>
55             {
56                 register
57                     .WithValueField(0, 8, name: $"ADDR_B{i} (Address Byte {i})",
58                         valueProviderCallback: _ => (byte)BitHelper.GetValue(userModeAccessAddress, i * 8, 8),
59                         writeCallback: (_, value) => BitHelper.SetMaskedValue(ref userModeAccessAddress, (byte)value, i * 8, 8));
60             });
61 
62             Registers.UMADataByte0_0.DefineMany(this, 4, (register, i) =>
63             {
64                 register
65                     .WithValueField(0, 8, name: $"DAT_B{i} (Data Byte {i})",
66                         valueProviderCallback: _ => (byte)BitHelper.GetValue(userModeAccessData, i * 8, 8),
67                         writeCallback: (_, value) => BitHelper.SetMaskedValue(ref userModeAccessData, (byte)value, i * 8, 8));
68             });
69 
70             Registers.UMAControlAndStatus.Define(this, 0x40)
71                 .WithValueField(0, 3, out var dataWidth, name: "D_SIZE (Data Field Size Select)")
72                 .WithFlag(3, out var addressWidthSelect, name: "A_SIZE (Address Field Size Select)")
73                 .WithFlag(4, out var skipCodeField, name: "C_SIZE (Code Field Size Select)")
74                 .WithFlag(5, out var isWrite, name: "RD_WR (Read/Write Select)")
75                 .WithReservedBits(6, 1, allowedValue: 0x1)
76                 .WithFlag(7, out var umaTransactionStart, name: "EXEC_DONE (Operation Execute/Done)")
77                 .WithWriteCallback((_, __) =>
78                     {
79                         if(!umaTransactionStart.Value)
80                         {
81                             return;
82                         }
83                         umaTransactionStart.Value = false;
84 
85                         if(userModeAccessLocked)
86                         {
87                             this.ErrorLog("Attempted to start a UMA transaction while UMA_LOCK is active");
88                             return;
89                         }
90 
91                         var addressWidth = (int)userModeAccessAddressSize.Value;
92                         if(addressWidthSelect.Value)
93                         {
94                             addressWidth = use4ByteAddress ? 4 : 3;
95                         }
96 
97                         var skipCode = skipCodeField.Value;
98                         if(isWrite.Value)
99                         {
100                             skipCode = false;
101                         }
102 
103                         PerformUserModeAccessTransaction(addressWidth, (int)dataWidth.Value, isWrite.Value, skipCode);
104                     });
105 
106             Registers.UMAExtendedControlAndStatus.Define(this, 0x3)
107                 .WithReservedBits(0, 1, allowedValue: 0x1)
108                 .WithFlag(1, out softwareChipSelect, name: "SW_CS1 (Software Controlled Chip-Select 1n)",
109                     changeCallback: (_, value) =>
110                         {
111                             if(!value)
112                             {
113                                 return;
114                             }
115 
116                             RegisteredPeripheral?.FinishTransmission();
117                         })
118                 .WithTaggedFlag("SEC_CS (Secondary Chip-Select)", 2)
119                 .WithFlag(3, name: "UMA_LOCK (UMA Operation Lock)",
120                     valueProviderCallback: _ => userModeAccessLocked,
121                     writeCallback: (_, value) =>
122                         {
123                             if(userModeAccessLocked)
124                             {
125                                 return;
126                             }
127 
128                             userModeAccessLocked = value;
129                         })
130                 .WithValueField(4, 3, out userModeAccessAddressSize, name: "UMA_ADDR_SIZE (Address Field Size Select)")
131                 .WithReservedBits(7, 1);
132 
133             Registers.UMADataByte1_0.DefineMany(this, 4, (register, i) =>
134             {
135                 register
136                     .WithValueField(0, 8, FieldMode.Read, name: $"DAT_B{i} (Data Byte {i})",
137                         valueProviderCallback: _ => (byte)BitHelper.GetValue(userModeAccessData, i * 8, 8));
138             });
139 
140             Registers.UMAAddressByte1_0.DefineMany(this, 4, (register, i) =>
141             {
142                 register
143                     .WithValueField(0, 8, name: $"ADDR_B{i} (Address Byte {i})",
144                         valueProviderCallback: _ => (byte)BitHelper.GetValue(userModeAccessAddress, i * 8, 8),
145                         writeCallback: (_, value) => BitHelper.SetMaskedValue(ref userModeAccessAddress, (byte)value, i * 8, 8));
146             });
147 
148             Registers.SPI1Device.Define(this)
149                 .WithTag("SPI1_LO_DEV_SIZE (SPI0 Low Device size)", 0, 4)
150                 .WithReservedBits(4, 2)
151                 .WithFlag(6, out var use4ByteCS10, name: "FOUR_BADDR_CS10 (Four Bytes Address for Chip-Select 10)")
152                 .WithFlag(7, out var use4ByteCS11, name: "FOUR_BADDR_CS11 (Four Bytes Address for Chip-Select 11)")
153                 .WithWriteCallback((_, __) =>
154                     {
155                         use4ByteAddress = use4ByteCS10.Value || use4ByteCS11.Value;
156                     });
157         }
158 
PerformUserModeAccessTransaction(int addressWidth, int dataWidth, bool isWrite, bool skipCode)159         private void PerformUserModeAccessTransaction(int addressWidth, int dataWidth, bool isWrite, bool skipCode)
160         {
161             if(RegisteredPeripheral == null)
162             {
163                 this.ErrorLog("Attempted to perform a UMA transaction with no peripheral attached");
164                 return;
165             }
166 
167             if(!skipCode)
168             {
169                 RegisteredPeripheral.Transmit((byte)userModeAccessCode.Value);
170             }
171 
172             for(var i = 0; i < addressWidth; i++)
173             {
174                 RegisteredPeripheral.Transmit((byte)BitHelper.GetValue(userModeAccessAddress, i * 8, 8));
175             }
176 
177             for(var i = 0; i < dataWidth; i++)
178             {
179                 var value = RegisteredPeripheral.Transmit((byte)BitHelper.GetValue(userModeAccessData, i * 8, 8));
180                 if(!isWrite)
181                 {
182                     BitHelper.SetMaskedValue(ref userModeAccessData, value, i * 8, 8);
183                 }
184             }
185 
186             if(softwareChipSelect.Value)
187             {
188                 RegisteredPeripheral.FinishTransmission();
189             }
190         }
191 
192         private IValueRegisterField userModeAccessCode;
193         private IValueRegisterField userModeAccessAddressSize;
194         private IFlagRegisterField softwareChipSelect;
195 
196         private uint userModeAccessAddress;
197         private uint userModeAccessData;
198         private bool userModeAccessLocked;
199         private bool use4ByteAddress;
200 
201         private enum Registers
202         {
203             BurstConfiguration          = 0x01, // BURST_CFG
204             ResponseConfiguration       = 0x02, // RESP_CFG
205             SPIFlashConfiguration       = 0x14, // SPI_FL_CFG
206             UMACodeByte                 = 0x16, // UMA_CODE
207             UMAAddressByte0_0           = 0x17, // UMA_AB0
208             UMAAddressByte0_1           = 0x18, // UMA_AB1
209             UMAAddressByte0_2           = 0x19, // UMA_AB2
210             UMADataByte0_0              = 0x1A, // UMA_DB0
211             UMADataByte0_1              = 0x1B, // UMA_DB1
212             UMADataByte0_2              = 0x1C, // UMA_DB2
213             UMADataByte0_3              = 0x1D, // UMA_DB3
214             UMAControlAndStatus         = 0x1E, // UMA_CTS
215             UMAExtendedControlAndStatus = 0x1F, // UMA_ECTS
216             UMADataByte1_0              = 0x20, // UMA_DB0 NOTE: This is a read-only mirror of the UMA_DB0-3
217             UMADataByte1_1              = 0x21, // UMA_DB1
218             UMADataByte1_2              = 0x22, // UMA_DB2
219             UMADataByte1_3              = 0x23, // UMA_DB3
220             CRCControl                  = 0x26, // CRCCON
221             CRCResult                   = 0x27, // CRCRSLT
222             FIUReadCommand              = 0x30, // FIU_RD_CMD
223             FIUDummyCycle               = 0x32, // FIU_DMM_CYC
224             FIUExtendedConfiguration    = 0x33, // FIU_EXT_CFG
225             UMAAddressByte1_0           = 0x34, // UMA_AB0 NOTE: Only to be used with external flash
226             UMAAddressByte1_1           = 0x35, // UMA_AB1       and when UMA_ADDR_SIZE is 4
227             UMAAddressByte1_2           = 0x36, // UMA_AB2
228             UMAAddressByte1_3           = 0x37, // UMA_AB3
229             SPI1Device                  = 0x3D, // SPI1_DEV
230         }
231     }
232 }
233 
234