blob: 0cfbfbf98faebc90a094476f911e08cd9d1883bb [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
AppaRao Pulic532f552019-07-05 15:23:50 +053017#include "pfr.hpp"
AppaRao Puli67d184c2020-05-29 00:48:33 +053018
AppaRao Pulic532f552019-07-05 15:23:50 +053019#include "file.hpp"
AppaRao Puli4b639a22019-10-01 18:12:59 +053020#include "spiDev.hpp"
AppaRao Pulic532f552019-07-05 15:23:50 +053021
AppaRao Puli67d184c2020-05-29 00:48:33 +053022#include <iomanip>
23#include <iostream>
24#include <sstream>
25
AppaRao Pulic532f552019-07-05 15:23:50 +053026namespace pfr
27{
28// TODO: Dynamically pull these values from configuration
29// entity-manager, when needed
30static constexpr int i2cBusNumber = 4;
Vikram Bodireddya9d68c02019-11-12 16:26:29 +053031// below given is 7bit address. Its 8bit addr is 0x70
32static constexpr int i2cSlaveAddress = 0x38;
AppaRao Pulic532f552019-07-05 15:23:50 +053033
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);
AppaRao Puli90fb45c2020-01-21 16:50:53 +053082 // Major and Minor versions should be binary encoded strings.
AppaRao Pulic532f552019-07-05 15:23:50 +053083 std::string version =
AppaRao Puli90fb45c2020-01-21 16:50:53 +053084 std::to_string(majorVer) + "." + std::to_string(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 }
AppaRao Puli90fb45c2020-01-21 16:50:53 +0530145
146 // Version format: <major>.<minor>-<build bum>-g<build hash>
147 // Example: 0.11-7-g1e5c2d
148 // Major, minor and build numberare BCD encoded.
149 std::string version =
150 std::to_string(ver[0]) + "." + std::to_string(ver[1]) + "-" +
151 std::to_string(buildNo) + "-g" + toHexString(buildHash[0]) +
152 toHexString(buildHash[1]) + toHexString(buildHash[2]);
AppaRao Puli4b639a22019-10-01 18:12:59 +0530153 return version;
154}
155
156std::string getFirmwareVersion(const ImageType& imgType)
157{
158 switch (imgType)
159 {
Vikram Bodireddy3c6c8c32019-12-05 11:06:15 +0530160 case (ImageType::cpldActive):
161 case (ImageType::cpldRecovery):
AppaRao Puli4b639a22019-10-01 18:12:59 +0530162 {
Vikram Bodireddy3c6c8c32019-12-05 11:06:15 +0530163 // TO-DO: Need to update once CPLD supported Firmware is available
AppaRao Puli4b639a22019-10-01 18:12:59 +0530164 return readVersionFromCPLD(cpldROTVersion, cpldROTSvn);
165 }
166 case (ImageType::biosActive):
167 {
168 return readVersionFromCPLD(pchActiveMajorVersion,
169 pchActiveMinorVersion);
170 }
171 case (ImageType::biosRecovery):
172 {
173 return readVersionFromCPLD(pchRecoveryMajorVersion,
174 pchRecoveryMinorVersion);
175 }
176 case (ImageType::bmcActive):
177 case (ImageType::bmcRecovery):
178 {
179 return readBMCVersionFromSPI(imgType);
180 }
181 default:
182 // Invalid image Type.
183 return "";
184 }
185}
186
AppaRao Pulic532f552019-07-05 15:23:50 +0530187int getProvisioningStatus(bool& ufmLocked, bool& ufmProvisioned)
188{
189 try
190 {
191 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
192 uint8_t provStatus = cpldDev.i2cReadByteData(provisioningStatus);
193 ufmLocked = (provStatus & ufmLockedMask);
194 ufmProvisioned = (provStatus & ufmProvisionedMask);
195 return 0;
196 }
197 catch (const std::exception& e)
198 {
199 phosphor::logging::log<phosphor::logging::level::ERR>(
200 "Exception caught in getProvisioningStatus.",
201 phosphor::logging::entry("MSG=%s", e.what()));
202 return -1;
203 }
204}
205
AppaRao Pulidbe184d2019-10-09 18:04:22 +0530206int readCpldReg(const ActionType& action, uint8_t& value)
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530207{
208 uint8_t cpldReg;
209
210 switch (action)
211 {
212 case (ActionType::recoveryCount):
213 cpldReg = recoveryCount;
214 break;
215 case (ActionType::recoveryReason):
216 cpldReg = lastRecoveryReason;
217 break;
218 case (ActionType::panicCount):
219 cpldReg = panicEventCount;
220 break;
221 case (ActionType::panicReason):
222 cpldReg = panicEventReason;
223 break;
224 case (ActionType::majorError):
225 cpldReg = majorErrorCode;
226 break;
227 case (ActionType::minorError):
228 cpldReg = minorErrorCode;
229 break;
230
231 default:
232 phosphor::logging::log<phosphor::logging::level::ERR>(
233 "Invalid CPLD read action.");
234 return -1;
235 }
236
237 try
238 {
239 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
240 value = cpldDev.i2cReadByteData(cpldReg);
241 return 0;
242 }
243 catch (const std::exception& e)
244 {
245 phosphor::logging::log<phosphor::logging::level::ERR>(
246 "Exception caught in readCpldReg.",
247 phosphor::logging::entry("MSG=%s", e.what()));
248 return -1;
249 }
250}
251
AppaRao Puli46cead92019-07-22 16:50:09 +0530252int setBMCBootCheckpoint(const uint8_t checkPoint)
253{
254 try
255 {
256 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
257 cpldDev.i2cWriteByteData(bmcBootCheckpoint, checkPoint);
AppaRao Pulib7e172c2019-12-13 14:46:25 +0530258 phosphor::logging::log<phosphor::logging::level::INFO>(
259 "Successfully set the PFR CPLD checkpoint 9.");
AppaRao Puli46cead92019-07-22 16:50:09 +0530260 return 0;
261 }
262 catch (const std::exception& e)
263 {
264 phosphor::logging::log<phosphor::logging::level::ERR>(
265 "Exception caught in setBMCBootCheckout.",
266 phosphor::logging::entry("MSG=%s", e.what()));
267 return -1;
268 }
269}
270
AppaRao Pulic532f552019-07-05 15:23:50 +0530271} // namespace pfr