blob: 5e43d48dce22e9b072ad544e8d03dfe94027594c [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;
Vikram Bodireddya9d68c02019-11-12 16:26:29 +053032// below given is 7bit address. Its 8bit addr is 0x70
33static constexpr int i2cSlaveAddress = 0x38;
AppaRao Pulic532f552019-07-05 15:23:50 +053034
35// CPLD mailbox registers
36static constexpr uint8_t cpldROTVersion = 0x01;
37static constexpr uint8_t cpldROTSvn = 0x02;
38static constexpr uint8_t platformState = 0x03;
39static constexpr uint8_t recoveryCount = 0x04;
40static constexpr uint8_t lastRecoveryReason = 0x05;
41static constexpr uint8_t panicEventCount = 0x06;
42static constexpr uint8_t panicEventReason = 0x07;
43static constexpr uint8_t majorErrorCode = 0x08;
44static constexpr uint8_t minorErrorCode = 0x09;
45static constexpr uint8_t provisioningStatus = 0x0A;
AppaRao Puli46cead92019-07-22 16:50:09 +053046static constexpr uint8_t bmcBootCheckpoint = 0x0F;
AppaRao Pulia04c8252019-07-31 22:59:28 +053047static constexpr uint8_t pchActiveMajorVersion = 0x15;
48static constexpr uint8_t pchActiveMinorVersion = 0x16;
AppaRao Pulia04c8252019-07-31 22:59:28 +053049static constexpr uint8_t pchRecoveryMajorVersion = 0x1B;
50static constexpr uint8_t pchRecoveryMinorVersion = 0x1C;
AppaRao Pulic532f552019-07-05 15:23:50 +053051
52static constexpr uint8_t ufmLockedMask = (0x1 << 0x04);
53static constexpr uint8_t ufmProvisionedMask = (0x1 << 0x05);
54
AppaRao Puli4b639a22019-10-01 18:12:59 +053055// PFR MTD devices
56static constexpr const char* bmcActiveImgPfmMTDDev = "/dev/mtd/pfm";
57static constexpr const char* bmcRecoveryImgMTDDev = "/dev/mtd/rc-image";
58
59// PFM offset in full image
60static constexpr const uint32_t pfmBaseOffsetInImage = 0x400;
61
62// OFFSET values in PFM
63static constexpr const uint32_t verOffsetInPFM = 0x406;
64static constexpr const uint32_t buildNumOffsetInPFM = 0x40C;
65static constexpr const uint32_t buildHashOffsetInPFM = 0x40D;
66
AppaRao Pulidbe184d2019-10-09 18:04:22 +053067std::string toHexString(const uint8_t val)
AppaRao Pulic532f552019-07-05 15:23:50 +053068{
69 std::stringstream stream;
AppaRao Pulidbe184d2019-10-09 18:04:22 +053070 stream << std::setfill('0') << std::setw(2) << std::hex
71 << static_cast<int>(val);
AppaRao Pulic532f552019-07-05 15:23:50 +053072 return stream.str();
73}
74
AppaRao Puli4b639a22019-10-01 18:12:59 +053075static std::string readVersionFromCPLD(const uint8_t majorReg,
76 const uint8_t minorReg)
AppaRao Pulic532f552019-07-05 15:23:50 +053077{
78 try
79 {
AppaRao Pulic532f552019-07-05 15:23:50 +053080 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
81 uint8_t majorVer = cpldDev.i2cReadByteData(majorReg);
82 uint8_t minorVer = cpldDev.i2cReadByteData(minorReg);
83 std::string version =
AppaRao Pulidbe184d2019-10-09 18:04:22 +053084 toHexString(majorVer) + "." + toHexString(minorVer);
AppaRao Pulic532f552019-07-05 15:23:50 +053085 return version;
86 }
87 catch (const std::exception& e)
88 {
89 phosphor::logging::log<phosphor::logging::level::ERR>(
AppaRao Puli4b639a22019-10-01 18:12:59 +053090 "Exception caught in readVersionFromCPLD.",
AppaRao Pulic532f552019-07-05 15:23:50 +053091 phosphor::logging::entry("MSG=%s", e.what()));
92 return "";
93 }
94}
95
AppaRao Puli4b639a22019-10-01 18:12:59 +053096static std::string readBMCVersionFromSPI(const ImageType& imgType)
97{
98 std::string mtdDev;
99 uint32_t verOffset = verOffsetInPFM;
100 uint32_t bldNumOffset = buildNumOffsetInPFM;
101 uint32_t bldHashOffset = buildHashOffsetInPFM;
102
103 if (imgType == ImageType::bmcActive)
104 {
105 // For Active image, PFM is emulated as separate MTD device.
106 mtdDev = bmcActiveImgPfmMTDDev;
107 }
108 else if (imgType == ImageType::bmcRecovery)
109 {
110 // For Recovery image, PFM is part of compressed Image
111 // at offset 0x400.
112 mtdDev = bmcRecoveryImgMTDDev;
113 verOffset += pfmBaseOffsetInImage;
114 bldNumOffset += pfmBaseOffsetInImage;
115 bldHashOffset += pfmBaseOffsetInImage;
116 }
117 else
118 {
119 phosphor::logging::log<phosphor::logging::level::ERR>(
120 "Invalid image type passed to readBMCVersionFromSPI.");
121 return "";
122 }
123
124 uint8_t buildNo = 0;
125 std::array<uint8_t, 2> ver;
126 std::array<uint8_t, 3> buildHash;
127
128 try
129 {
130 SPIDev spiDev(mtdDev);
131 spiDev.spiReadData(verOffset, ver.size(),
132 reinterpret_cast<void*>(ver.data()));
133 spiDev.spiReadData(bldNumOffset, sizeof(buildNo),
134 reinterpret_cast<void*>(&buildNo));
135 spiDev.spiReadData(bldHashOffset, buildHash.size(),
136 reinterpret_cast<void*>(buildHash.data()));
137 }
138 catch (const std::exception& e)
139 {
140 phosphor::logging::log<phosphor::logging::level::ERR>(
141 "Exception caught in readBMCVersionFromSPI.",
142 phosphor::logging::entry("MSG=%s", e.what()));
143 return "";
144 }
145 // Version format: <major>.<minor>-<build bum>-<build hash>
146 // Example: 00.11-07-1e5c2d
147 std::string version = toHexString(ver[0]) + "." + toHexString(ver[1]) +
148 "-" + toHexString(buildNo) + "-" +
149 toHexString(buildHash[0]) +
150 toHexString(buildHash[1]) + toHexString(buildHash[2]);
151 return version;
152}
153
154std::string getFirmwareVersion(const ImageType& imgType)
155{
156 switch (imgType)
157 {
158 case (ImageType::cpld):
159 {
160 return readVersionFromCPLD(cpldROTVersion, cpldROTSvn);
161 }
162 case (ImageType::biosActive):
163 {
164 return readVersionFromCPLD(pchActiveMajorVersion,
165 pchActiveMinorVersion);
166 }
167 case (ImageType::biosRecovery):
168 {
169 return readVersionFromCPLD(pchRecoveryMajorVersion,
170 pchRecoveryMinorVersion);
171 }
172 case (ImageType::bmcActive):
173 case (ImageType::bmcRecovery):
174 {
175 return readBMCVersionFromSPI(imgType);
176 }
177 default:
178 // Invalid image Type.
179 return "";
180 }
181}
182
AppaRao Pulic532f552019-07-05 15:23:50 +0530183int getProvisioningStatus(bool& ufmLocked, bool& ufmProvisioned)
184{
185 try
186 {
187 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
188 uint8_t provStatus = cpldDev.i2cReadByteData(provisioningStatus);
189 ufmLocked = (provStatus & ufmLockedMask);
190 ufmProvisioned = (provStatus & ufmProvisionedMask);
191 return 0;
192 }
193 catch (const std::exception& e)
194 {
195 phosphor::logging::log<phosphor::logging::level::ERR>(
196 "Exception caught in getProvisioningStatus.",
197 phosphor::logging::entry("MSG=%s", e.what()));
198 return -1;
199 }
200}
201
AppaRao Pulidbe184d2019-10-09 18:04:22 +0530202int readCpldReg(const ActionType& action, uint8_t& value)
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530203{
204 uint8_t cpldReg;
205
206 switch (action)
207 {
208 case (ActionType::recoveryCount):
209 cpldReg = recoveryCount;
210 break;
211 case (ActionType::recoveryReason):
212 cpldReg = lastRecoveryReason;
213 break;
214 case (ActionType::panicCount):
215 cpldReg = panicEventCount;
216 break;
217 case (ActionType::panicReason):
218 cpldReg = panicEventReason;
219 break;
220 case (ActionType::majorError):
221 cpldReg = majorErrorCode;
222 break;
223 case (ActionType::minorError):
224 cpldReg = minorErrorCode;
225 break;
226
227 default:
228 phosphor::logging::log<phosphor::logging::level::ERR>(
229 "Invalid CPLD read action.");
230 return -1;
231 }
232
233 try
234 {
235 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
236 value = cpldDev.i2cReadByteData(cpldReg);
237 return 0;
238 }
239 catch (const std::exception& e)
240 {
241 phosphor::logging::log<phosphor::logging::level::ERR>(
242 "Exception caught in readCpldReg.",
243 phosphor::logging::entry("MSG=%s", e.what()));
244 return -1;
245 }
246}
247
AppaRao Puli46cead92019-07-22 16:50:09 +0530248int setBMCBootCheckpoint(const uint8_t checkPoint)
249{
250 try
251 {
252 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
253 cpldDev.i2cWriteByteData(bmcBootCheckpoint, checkPoint);
254 return 0;
255 }
256 catch (const std::exception& e)
257 {
258 phosphor::logging::log<phosphor::logging::level::ERR>(
259 "Exception caught in setBMCBootCheckout.",
260 phosphor::logging::entry("MSG=%s", e.what()));
261 return -1;
262 }
263}
264
AppaRao Pulic532f552019-07-05 15:23:50 +0530265} // namespace pfr
266} // namespace intel