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.Linq; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Core; 13 using Antmicro.Renode.Core.Structure.Registers; 14 using Antmicro.Renode.Peripherals.Memory; 15 16 namespace Antmicro.Renode.Peripherals.MTD 17 { 18 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)] 19 public class CC2538FlashController : IDoubleWordPeripheral, IKnownSize 20 { CC2538FlashController(IMachine machine, MappedMemory flash)21 public CC2538FlashController(IMachine machine, MappedMemory flash) 22 { 23 this.flash = flash; 24 var registersMap = new Dictionary<long, DoubleWordRegister> 25 { 26 {(long)Registers.FlashControl, new DoubleWordRegister(this, 0x4) 27 .WithFlag(0, valueProviderCallback: _ => false, changeCallback: (_, value) => 28 { 29 if(value) 30 { 31 Erase(); 32 } 33 }, name: "ERASE") 34 .WithFlag(1, out write, name: "WRITE") 35 .WithTag("CACHE_MODE", 2, 2) 36 .WithReservedBits(4, 1) 37 .WithTag("ABORT", 5, 1) 38 .WithFlag(6, FieldMode.Read, name: "FULL") 39 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => write.Value, name: "BUSY") 40 .WithTag("SEL_INFO_PAGE", 8, 1) 41 .WithTag("UPPER_PAGE_ACCESS", 9, 1) 42 .WithReservedBits(10, 22) 43 }, 44 {(long)Registers.FlashAddress, new DoubleWordRegister(this) 45 .WithValueField(0, 16, valueProviderCallback: _ => writeAddress >> 2, writeCallback: (_, value) => { writeAddress = (uint)value; }, name : "FADDR") 46 .WithReservedBits(17, 15) 47 }, 48 {(long)Registers.FlashData, new DoubleWordRegister(this) 49 .WithValueField(0, 32, FieldMode.Write, writeCallback: (_, value) => Write((uint)value), name: "FWDATA") 50 }, 51 {(long)Registers.DieConfig0, new DoubleWordRegister(this, 0xB9640580) 52 .WithValueField(0, 32, FieldMode.Read) 53 }, 54 {(long)Registers.DieConfig1, new DoubleWordRegister(this) 55 .WithValueField(0, 32, FieldMode.Read) 56 }, 57 {(long)Registers.DieConfig2, new DoubleWordRegister(this, 0x2000) 58 .WithValueField(0, 32, FieldMode.Read) 59 }, 60 }; 61 62 registers = new DoubleWordRegisterCollection(this, registersMap); 63 Reset(); 64 } 65 ReadDoubleWord(long offset)66 public uint ReadDoubleWord(long offset) 67 { 68 return registers.Read(offset); 69 } 70 WriteDoubleWord(long offset, uint value)71 public void WriteDoubleWord(long offset, uint value) 72 { 73 registers.Write(offset, value); 74 } 75 Reset()76 public void Reset() 77 { 78 registers.Reset(); 79 writeAddress = 0; 80 // Clear the whole flash memory 81 for(uint i = 0; i < PageNumber; ++i) 82 { 83 flash.WriteBytes(0x800 * i, ErasePattern, 0, PageSize); 84 } 85 } 86 87 public long Size => 0x1000; 88 Write(uint newValue)89 private void Write(uint newValue) 90 { 91 var targetAddress = writeAddress; 92 if(!write.Value) 93 { 94 this.Log(LogLevel.Warning, "Writing 0x{0:X} to 0x{1:X} when not in write mode", newValue, targetAddress); 95 return; 96 } 97 if(targetAddress > flash.Size) 98 { 99 this.Log(LogLevel.Error, "Trying to write outside the flash memory at 0x{0:X}", targetAddress); 100 return; 101 } 102 var oldValue = flash.ReadDoubleWord(targetAddress); 103 if(oldValue != 0xffffffff) 104 { 105 this.Log(LogLevel.Warning, "Writing to a dirty word at address 0x{0:X}", targetAddress); 106 } 107 this.Log(LogLevel.Noisy, "Writing 0x{0:X} to 0x{1:X}", newValue, targetAddress); 108 flash.WriteDoubleWord(targetAddress, oldValue & newValue); 109 write.Value = false; 110 } 111 Erase()112 private void Erase() 113 { 114 flash.WriteBytes((long)((writeAddress) & ~(PageSize - 1)), ErasePattern, 0, PageSize); 115 this.Log(LogLevel.Noisy, "Erasing on address 0x{0:X}", (writeAddress & ~(PageSize - 1))); 116 } 117 118 private uint writeAddress; 119 private readonly IFlagRegisterField write; 120 121 private readonly DoubleWordRegisterCollection registers; 122 private readonly MappedMemory flash; 123 124 private const int PageSize = 2048; 125 private const int PageNumber = 256; 126 private readonly byte[] ErasePattern = (byte[])Enumerable.Repeat((byte)0xFF, PageSize).ToArray(); 127 128 private enum Registers : long 129 { 130 FlashControl = 0x08, 131 FlashAddress = 0x0c, 132 FlashData = 0x10, 133 DieConfig0 = 0x14, 134 DieConfig1 = 0x18, 135 DieConfig2 = 0x1c 136 } 137 } 138 } 139