blob: 07b759325504f5ec7c9e4900e61781682152c488 [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);
AppaRao Puli90fb45c2020-01-21 16:50:53 +053083 // Major and Minor versions should be binary encoded strings.
AppaRao Pulic532f552019-07-05 15:23:50 +053084 std::string version =
AppaRao Puli90fb45c2020-01-21 16:50:53 +053085 std::to_string(majorVer) + "." + std::to_string(minorVer);
AppaRao Pulic532f552019-07-05 15:23:50 +053086 return version;
87 }
88 catch (const std::exception& e)
89 {
90 phosphor::logging::log<phosphor::logging::level::ERR>(
AppaRao Puli4b639a22019-10-01 18:12:59 +053091 "Exception caught in readVersionFromCPLD.",
AppaRao Pulic532f552019-07-05 15:23:50 +053092 phosphor::logging::entry("MSG=%s", e.what()));
93 return "";
94 }
95}
96
AppaRao Puli4b639a22019-10-01 18:12:59 +053097static std::string readBMCVersionFromSPI(const ImageType& imgType)
98{
99 std::string mtdDev;
100 uint32_t verOffset = verOffsetInPFM;
101 uint32_t bldNumOffset = buildNumOffsetInPFM;
102 uint32_t bldHashOffset = buildHashOffsetInPFM;
103
104 if (imgType == ImageType::bmcActive)
105 {
106 // For Active image, PFM is emulated as separate MTD device.
107 mtdDev = bmcActiveImgPfmMTDDev;
108 }
109 else if (imgType == ImageType::bmcRecovery)
110 {
111 // For Recovery image, PFM is part of compressed Image
112 // at offset 0x400.
113 mtdDev = bmcRecoveryImgMTDDev;
114 verOffset += pfmBaseOffsetInImage;
115 bldNumOffset += pfmBaseOffsetInImage;
116 bldHashOffset += pfmBaseOffsetInImage;
117 }
118 else
119 {
120 phosphor::logging::log<phosphor::logging::level::ERR>(
121 "Invalid image type passed to readBMCVersionFromSPI.");
122 return "";
123 }
124
125 uint8_t buildNo = 0;
126 std::array<uint8_t, 2> ver;
127 std::array<uint8_t, 3> buildHash;
128
129 try
130 {
131 SPIDev spiDev(mtdDev);
132 spiDev.spiReadData(verOffset, ver.size(),
133 reinterpret_cast<void*>(ver.data()));
134 spiDev.spiReadData(bldNumOffset, sizeof(buildNo),
135 reinterpret_cast<void*>(&buildNo));
136 spiDev.spiReadData(bldHashOffset, buildHash.size(),
137 reinterpret_cast<void*>(buildHash.data()));
138 }
139 catch (const std::exception& e)
140 {
141 phosphor::logging::log<phosphor::logging::level::ERR>(
142 "Exception caught in readBMCVersionFromSPI.",
143 phosphor::logging::entry("MSG=%s", e.what()));
144 return "";
145 }
AppaRao Puli90fb45c2020-01-21 16:50:53 +0530146
147 // Version format: <major>.<minor>-<build bum>-g<build hash>
148 // Example: 0.11-7-g1e5c2d
149 // Major, minor and build numberare BCD encoded.
150 std::string version =
151 std::to_string(ver[0]) + "." + std::to_string(ver[1]) + "-" +
152 std::to_string(buildNo) + "-g" + toHexString(buildHash[0]) +
153 toHexString(buildHash[1]) + toHexString(buildHash[2]);
AppaRao Puli4b639a22019-10-01 18:12:59 +0530154 return version;
155}
156
157std::string getFirmwareVersion(const ImageType& imgType)
158{
159 switch (imgType)
160 {
Vikram Bodireddy3c6c8c32019-12-05 11:06:15 +0530161 case (ImageType::cpldActive):
162 case (ImageType::cpldRecovery):
AppaRao Puli4b639a22019-10-01 18:12:59 +0530163 {
Vikram Bodireddy3c6c8c32019-12-05 11:06:15 +0530164 // TO-DO: Need to update once CPLD supported Firmware is available
AppaRao Puli4b639a22019-10-01 18:12:59 +0530165 return readVersionFromCPLD(cpldROTVersion, cpldROTSvn);
166 }
167 case (ImageType::biosActive):
168 {
169 return readVersionFromCPLD(pchActiveMajorVersion,
170 pchActiveMinorVersion);
171 }
172 case (ImageType::biosRecovery):
173 {
174 return readVersionFromCPLD(pchRecoveryMajorVersion,
175 pchRecoveryMinorVersion);
176 }
177 case (ImageType::bmcActive):
178 case (ImageType::bmcRecovery):
179 {
180 return readBMCVersionFromSPI(imgType);
181 }
182 default:
183 // Invalid image Type.
184 return "";
185 }
186}
187
AppaRao Pulic532f552019-07-05 15:23:50 +0530188int getProvisioningStatus(bool& ufmLocked, bool& ufmProvisioned)
189{
190 try
191 {
192 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
193 uint8_t provStatus = cpldDev.i2cReadByteData(provisioningStatus);
194 ufmLocked = (provStatus & ufmLockedMask);
195 ufmProvisioned = (provStatus & ufmProvisionedMask);
196 return 0;
197 }
198 catch (const std::exception& e)
199 {
200 phosphor::logging::log<phosphor::logging::level::ERR>(
201 "Exception caught in getProvisioningStatus.",
202 phosphor::logging::entry("MSG=%s", e.what()));
203 return -1;
204 }
205}
206
AppaRao Pulidbe184d2019-10-09 18:04:22 +0530207int readCpldReg(const ActionType& action, uint8_t& value)
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530208{
209 uint8_t cpldReg;
210
211 switch (action)
212 {
213 case (ActionType::recoveryCount):
214 cpldReg = recoveryCount;
215 break;
216 case (ActionType::recoveryReason):
217 cpldReg = lastRecoveryReason;
218 break;
219 case (ActionType::panicCount):
220 cpldReg = panicEventCount;
221 break;
222 case (ActionType::panicReason):
223 cpldReg = panicEventReason;
224 break;
225 case (ActionType::majorError):
226 cpldReg = majorErrorCode;
227 break;
228 case (ActionType::minorError):
229 cpldReg = minorErrorCode;
230 break;
231
232 default:
233 phosphor::logging::log<phosphor::logging::level::ERR>(
234 "Invalid CPLD read action.");
235 return -1;
236 }
237
238 try
239 {
240 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
241 value = cpldDev.i2cReadByteData(cpldReg);
242 return 0;
243 }
244 catch (const std::exception& e)
245 {
246 phosphor::logging::log<phosphor::logging::level::ERR>(
247 "Exception caught in readCpldReg.",
248 phosphor::logging::entry("MSG=%s", e.what()));
249 return -1;
250 }
251}
252
AppaRao Puli46cead92019-07-22 16:50:09 +0530253int setBMCBootCheckpoint(const uint8_t checkPoint)
254{
255 try
256 {
257 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
258 cpldDev.i2cWriteByteData(bmcBootCheckpoint, checkPoint);
AppaRao Pulib7e172c2019-12-13 14:46:25 +0530259 phosphor::logging::log<phosphor::logging::level::INFO>(
260 "Successfully set the PFR CPLD checkpoint 9.");
AppaRao Puli46cead92019-07-22 16:50:09 +0530261 return 0;
262 }
263 catch (const std::exception& e)
264 {
265 phosphor::logging::log<phosphor::logging::level::ERR>(
266 "Exception caught in setBMCBootCheckout.",
267 phosphor::logging::entry("MSG=%s", e.what()));
268 return -1;
269 }
270}
271
AppaRao Pulic532f552019-07-05 15:23:50 +0530272} // namespace pfr
273} // namespace intel