blob: a61f72e8ed7167de6793094be97ccc18f1fe0deb [file] [log] [blame]
AppaRao Pulic532f552019-07-05 15:23:50 +05301/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include <unistd.h>
18#include <iostream>
19#include <sstream>
20#include <iomanip>
21#include "pfr.hpp"
22#include "file.hpp"
AppaRao Puli4b639a22019-10-01 18:12:59 +053023#include "spiDev.hpp"
AppaRao Pulic532f552019-07-05 15:23:50 +053024
25namespace intel
26{
27namespace pfr
28{
29// TODO: Dynamically pull these values from configuration
30// entity-manager, when needed
31static constexpr int i2cBusNumber = 4;
32static constexpr int i2cSlaveAddress = 0x70;
33
34// CPLD mailbox registers
35static constexpr uint8_t cpldROTVersion = 0x01;
36static constexpr uint8_t cpldROTSvn = 0x02;
37static constexpr uint8_t platformState = 0x03;
38static constexpr uint8_t recoveryCount = 0x04;
39static constexpr uint8_t lastRecoveryReason = 0x05;
40static constexpr uint8_t panicEventCount = 0x06;
41static constexpr uint8_t panicEventReason = 0x07;
42static constexpr uint8_t majorErrorCode = 0x08;
43static constexpr uint8_t minorErrorCode = 0x09;
44static constexpr uint8_t provisioningStatus = 0x0A;
AppaRao Puli46cead92019-07-22 16:50:09 +053045static constexpr uint8_t bmcBootCheckpoint = 0x0F;
AppaRao Pulia04c8252019-07-31 22:59:28 +053046static constexpr uint8_t pchActiveMajorVersion = 0x15;
47static constexpr uint8_t pchActiveMinorVersion = 0x16;
AppaRao Pulia04c8252019-07-31 22:59:28 +053048static constexpr uint8_t pchRecoveryMajorVersion = 0x1B;
49static constexpr uint8_t pchRecoveryMinorVersion = 0x1C;
AppaRao Pulic532f552019-07-05 15:23:50 +053050
51static constexpr uint8_t ufmLockedMask = (0x1 << 0x04);
52static constexpr uint8_t ufmProvisionedMask = (0x1 << 0x05);
53
AppaRao Puli4b639a22019-10-01 18:12:59 +053054// PFR MTD devices
55static constexpr const char* bmcActiveImgPfmMTDDev = "/dev/mtd/pfm";
56static constexpr const char* bmcRecoveryImgMTDDev = "/dev/mtd/rc-image";
57
58// PFM offset in full image
59static constexpr const uint32_t pfmBaseOffsetInImage = 0x400;
60
61// OFFSET values in PFM
62static constexpr const uint32_t verOffsetInPFM = 0x406;
63static constexpr const uint32_t buildNumOffsetInPFM = 0x40C;
64static constexpr const uint32_t buildHashOffsetInPFM = 0x40D;
65
AppaRao Pulidbe184d2019-10-09 18:04:22 +053066std::string toHexString(const uint8_t val)
AppaRao Pulic532f552019-07-05 15:23:50 +053067{
68 std::stringstream stream;
AppaRao Pulidbe184d2019-10-09 18:04:22 +053069 stream << std::setfill('0') << std::setw(2) << std::hex
70 << static_cast<int>(val);
AppaRao Pulic532f552019-07-05 15:23:50 +053071 return stream.str();
72}
73
AppaRao Puli4b639a22019-10-01 18:12:59 +053074static std::string readVersionFromCPLD(const uint8_t majorReg,
75 const uint8_t minorReg)
AppaRao Pulic532f552019-07-05 15:23:50 +053076{
77 try
78 {
AppaRao Pulic532f552019-07-05 15:23:50 +053079 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
80 uint8_t majorVer = cpldDev.i2cReadByteData(majorReg);
81 uint8_t minorVer = cpldDev.i2cReadByteData(minorReg);
82 std::string version =
AppaRao Pulidbe184d2019-10-09 18:04:22 +053083 toHexString(majorVer) + "." + toHexString(minorVer);
AppaRao Pulic532f552019-07-05 15:23:50 +053084 return version;
85 }
86 catch (const std::exception& e)
87 {
88 phosphor::logging::log<phosphor::logging::level::ERR>(
AppaRao Puli4b639a22019-10-01 18:12:59 +053089 "Exception caught in readVersionFromCPLD.",
AppaRao Pulic532f552019-07-05 15:23:50 +053090 phosphor::logging::entry("MSG=%s", e.what()));
91 return "";
92 }
93}
94
AppaRao Puli4b639a22019-10-01 18:12:59 +053095static std::string readBMCVersionFromSPI(const ImageType& imgType)
96{
97 std::string mtdDev;
98 uint32_t verOffset = verOffsetInPFM;
99 uint32_t bldNumOffset = buildNumOffsetInPFM;
100 uint32_t bldHashOffset = buildHashOffsetInPFM;
101
102 if (imgType == ImageType::bmcActive)
103 {
104 // For Active image, PFM is emulated as separate MTD device.
105 mtdDev = bmcActiveImgPfmMTDDev;
106 }
107 else if (imgType == ImageType::bmcRecovery)
108 {
109 // For Recovery image, PFM is part of compressed Image
110 // at offset 0x400.
111 mtdDev = bmcRecoveryImgMTDDev;
112 verOffset += pfmBaseOffsetInImage;
113 bldNumOffset += pfmBaseOffsetInImage;
114 bldHashOffset += pfmBaseOffsetInImage;
115 }
116 else
117 {
118 phosphor::logging::log<phosphor::logging::level::ERR>(
119 "Invalid image type passed to readBMCVersionFromSPI.");
120 return "";
121 }
122
123 uint8_t buildNo = 0;
124 std::array<uint8_t, 2> ver;
125 std::array<uint8_t, 3> buildHash;
126
127 try
128 {
129 SPIDev spiDev(mtdDev);
130 spiDev.spiReadData(verOffset, ver.size(),
131 reinterpret_cast<void*>(ver.data()));
132 spiDev.spiReadData(bldNumOffset, sizeof(buildNo),
133 reinterpret_cast<void*>(&buildNo));
134 spiDev.spiReadData(bldHashOffset, buildHash.size(),
135 reinterpret_cast<void*>(buildHash.data()));
136 }
137 catch (const std::exception& e)
138 {
139 phosphor::logging::log<phosphor::logging::level::ERR>(
140 "Exception caught in readBMCVersionFromSPI.",
141 phosphor::logging::entry("MSG=%s", e.what()));
142 return "";
143 }
144 // Version format: <major>.<minor>-<build bum>-<build hash>
145 // Example: 00.11-07-1e5c2d
146 std::string version = toHexString(ver[0]) + "." + toHexString(ver[1]) +
147 "-" + toHexString(buildNo) + "-" +
148 toHexString(buildHash[0]) +
149 toHexString(buildHash[1]) + toHexString(buildHash[2]);
150 return version;
151}
152
153std::string getFirmwareVersion(const ImageType& imgType)
154{
155 switch (imgType)
156 {
157 case (ImageType::cpld):
158 {
159 return readVersionFromCPLD(cpldROTVersion, cpldROTSvn);
160 }
161 case (ImageType::biosActive):
162 {
163 return readVersionFromCPLD(pchActiveMajorVersion,
164 pchActiveMinorVersion);
165 }
166 case (ImageType::biosRecovery):
167 {
168 return readVersionFromCPLD(pchRecoveryMajorVersion,
169 pchRecoveryMinorVersion);
170 }
171 case (ImageType::bmcActive):
172 case (ImageType::bmcRecovery):
173 {
174 return readBMCVersionFromSPI(imgType);
175 }
176 default:
177 // Invalid image Type.
178 return "";
179 }
180}
181
AppaRao Pulic532f552019-07-05 15:23:50 +0530182int getProvisioningStatus(bool& ufmLocked, bool& ufmProvisioned)
183{
184 try
185 {
186 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
187 uint8_t provStatus = cpldDev.i2cReadByteData(provisioningStatus);
188 ufmLocked = (provStatus & ufmLockedMask);
189 ufmProvisioned = (provStatus & ufmProvisionedMask);
190 return 0;
191 }
192 catch (const std::exception& e)
193 {
194 phosphor::logging::log<phosphor::logging::level::ERR>(
195 "Exception caught in getProvisioningStatus.",
196 phosphor::logging::entry("MSG=%s", e.what()));
197 return -1;
198 }
199}
200
AppaRao Pulidbe184d2019-10-09 18:04:22 +0530201int readCpldReg(const ActionType& action, uint8_t& value)
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530202{
203 uint8_t cpldReg;
204
205 switch (action)
206 {
207 case (ActionType::recoveryCount):
208 cpldReg = recoveryCount;
209 break;
210 case (ActionType::recoveryReason):
211 cpldReg = lastRecoveryReason;
212 break;
213 case (ActionType::panicCount):
214 cpldReg = panicEventCount;
215 break;
216 case (ActionType::panicReason):
217 cpldReg = panicEventReason;
218 break;
219 case (ActionType::majorError):
220 cpldReg = majorErrorCode;
221 break;
222 case (ActionType::minorError):
223 cpldReg = minorErrorCode;
224 break;
225
226 default:
227 phosphor::logging::log<phosphor::logging::level::ERR>(
228 "Invalid CPLD read action.");
229 return -1;
230 }
231
232 try
233 {
234 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
235 value = cpldDev.i2cReadByteData(cpldReg);
236 return 0;
237 }
238 catch (const std::exception& e)
239 {
240 phosphor::logging::log<phosphor::logging::level::ERR>(
241 "Exception caught in readCpldReg.",
242 phosphor::logging::entry("MSG=%s", e.what()));
243 return -1;
244 }
245}
246
AppaRao Puli46cead92019-07-22 16:50:09 +0530247int setBMCBootCheckpoint(const uint8_t checkPoint)
248{
249 try
250 {
251 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
252 cpldDev.i2cWriteByteData(bmcBootCheckpoint, checkPoint);
253 return 0;
254 }
255 catch (const std::exception& e)
256 {
257 phosphor::logging::log<phosphor::logging::level::ERR>(
258 "Exception caught in setBMCBootCheckout.",
259 phosphor::logging::entry("MSG=%s", e.what()));
260 return -1;
261 }
262}
263
AppaRao Pulic532f552019-07-05 15:23:50 +0530264} // namespace pfr
265} // namespace intel