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