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
getLatticeChipStr(latticeChip chip,latticeStringType stringType)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:
LatticeBaseCPLD(sdbusplus::async::context & ctx,const uint16_t bus,const uint8_t address,const std::string & chip,const std::string & target,const bool debugMode)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