1 #pragma once 2 #include "common/include/i2c/i2c.hpp" 3 4 #include <phosphor-logging/lg2.hpp> 5 6 #include <chrono> 7 #include <iostream> 8 #include <string_view> 9 #include <unordered_map> 10 #include <utility> 11 12 namespace phosphor::software::cpld 13 { 14 15 enum class latticeChip 16 { 17 LCMXO2_4000HC, 18 LCMXO3LF_2100C, 19 LCMXO3LF_4300C, 20 LCMXO3D_4300, 21 LCMXO3D_9400, 22 LFMXO5_25, 23 UNSUPPORTED = -1, 24 }; 25 26 enum class latticeStringType 27 { 28 typeString, 29 modelString, 30 }; 31 32 inline std::string getLatticeChipStr(latticeChip chip, 33 latticeStringType stringType) 34 { 35 static const std::unordered_map<latticeChip, std::string> chipStringMap = { 36 {latticeChip::LCMXO2_4000HC, "LCMXO2_4000HC"}, 37 {latticeChip::LCMXO3LF_2100C, "LCMXO3LF_2100C"}, 38 {latticeChip::LCMXO3LF_4300C, "LCMXO3LF_4300C"}, 39 {latticeChip::LCMXO3D_4300, "LCMXO3D_4300"}, 40 {latticeChip::LCMXO3D_9400, "LCMXO3D_9400"}, 41 {latticeChip::LFMXO5_25, "LFMXO5_25"}, 42 }; 43 auto chipString = chipStringMap.at(chip); 44 if (chipStringMap.find(chip) == chipStringMap.end()) 45 { 46 lg2::error("Unsupported chip enum: {CHIPENUM}", "CHIPENUM", chip); 47 return ""; 48 } 49 50 switch (stringType) 51 { 52 case latticeStringType::typeString: 53 return std::string("Lattice" + chipString + "Firmware"); 54 case latticeStringType::modelString: 55 std::replace(chipString.begin(), chipString.end(), '_', '-'); 56 return chipString; 57 default: 58 lg2::error("Unsupported string type: {STRINGTYPE}", "STRINGTYPE", 59 stringType); 60 return ""; 61 } 62 }; 63 64 enum class latticeChipFamily 65 { 66 XO2, 67 XO3, 68 XO5, 69 }; 70 71 struct cpldInfo 72 { 73 latticeChipFamily chipFamily; 74 std::vector<uint8_t> deviceId; 75 }; 76 77 const std::map<latticeChip, cpldInfo> supportedDeviceMap = { 78 {latticeChip::LCMXO2_4000HC, 79 {latticeChipFamily::XO2, {0x01, 0x2b, 0xc0, 0x43}}}, 80 {latticeChip::LCMXO3LF_2100C, 81 {latticeChipFamily::XO3, {0x61, 0x2b, 0xb0, 0x43}}}, 82 {latticeChip::LCMXO3LF_4300C, 83 {latticeChipFamily::XO3, {0x61, 0x2b, 0xc0, 0x43}}}, 84 {latticeChip::LCMXO3D_4300, 85 {latticeChipFamily::XO3, {0x01, 0x2e, 0x20, 0x43}}}, 86 {latticeChip::LCMXO3D_9400, 87 {latticeChipFamily::XO3, {0x21, 0x2e, 0x30, 0x43}}}, 88 {latticeChip::LFMXO5_25, {latticeChipFamily::XO5, {}}}, 89 }; 90 91 struct cpldI2cInfo 92 { 93 unsigned long int fuseQuantity; 94 unsigned int* userFlashMemory; 95 unsigned int version; 96 unsigned int checksum; 97 std::vector<uint8_t> cfgData; 98 std::vector<uint8_t> ufmData; 99 }; 100 101 enum cpldI2cCmd 102 { 103 commandEraseFlash = 0x0E, 104 commandDisableConfigInterface = 0x26, 105 commandReadStatusReg = 0x3C, 106 commandResetConfigFlash = 0x46, 107 commandProgramDone = 0x5E, 108 commandProgramPage = 0x70, 109 commandReadPage = 0x73, 110 commandEnableConfigMode = 0x74, 111 commandSetPageAddress = 0xB4, 112 commandReadFwVersion = 0xC0, 113 commandProgramUserCode = 0xC2, 114 commandReadDeviceId = 0xE0, 115 commandReadBusyFlag = 0xF0, 116 }; 117 118 constexpr std::chrono::milliseconds waitBusyTime(200); 119 120 class LatticeBaseCPLD 121 { 122 public: 123 LatticeBaseCPLD(sdbusplus::async::context& ctx, const uint16_t bus, 124 const uint8_t address, const std::string& chip, 125 const std::string& target, const bool debugMode) : 126 ctx(ctx), chip(chip), target(target), debugMode(debugMode), 127 i2cInterface(phosphor::i2c::I2C(bus, address)) 128 {} 129 virtual ~LatticeBaseCPLD() = default; 130 LatticeBaseCPLD(const LatticeBaseCPLD&) = delete; 131 LatticeBaseCPLD& operator=(const LatticeBaseCPLD&) = delete; 132 LatticeBaseCPLD(LatticeBaseCPLD&&) noexcept = delete; 133 LatticeBaseCPLD& operator=(LatticeBaseCPLD&&) noexcept = delete; 134 135 sdbusplus::async::task<bool> updateFirmware( 136 const uint8_t* image, size_t imageSize, 137 std::function<bool(int)> progressCallBack); 138 139 sdbusplus::async::task<bool> getVersion(std::string& version); 140 141 protected: 142 sdbusplus::async::context& ctx; 143 cpldI2cInfo fwInfo{}; 144 std::string chip; 145 std::string target; 146 std::vector<uint8_t> sumOnly; 147 bool isLCMXO3D = false; 148 bool debugMode = false; 149 phosphor::i2c::I2C i2cInterface; 150 151 virtual sdbusplus::async::task<bool> prepareUpdate(const uint8_t*, 152 size_t) = 0; 153 virtual sdbusplus::async::task<bool> doUpdate() = 0; 154 virtual sdbusplus::async::task<bool> finishUpdate() = 0; 155 156 bool jedFileParser(const uint8_t* image, size_t imageSize); 157 bool verifyChecksum(); 158 sdbusplus::async::task<bool> enableProgramMode(); 159 sdbusplus::async::task<bool> resetConfigFlash(); 160 sdbusplus::async::task<bool> programDone(); 161 sdbusplus::async::task<bool> disableConfigInterface(); 162 sdbusplus::async::task<bool> waitBusyAndVerify(); 163 164 private: 165 virtual sdbusplus::async::task<bool> readUserCode(uint32_t&) = 0; 166 sdbusplus::async::task<bool> readBusyFlag(uint8_t& busyFlag); 167 sdbusplus::async::task<bool> readStatusReg(uint8_t& statusReg); 168 static std::string uint32ToHexStr(uint32_t value); 169 }; 170 171 } // namespace phosphor::software::cpld 172