blob: a5316ba275332051b9bc07b0cc0e2d6ca3253d4f [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 {
Vikram Bodireddy3c6c8c32019-12-05 11:06:15 +0530158 case (ImageType::cpldActive):
159 case (ImageType::cpldRecovery):
AppaRao Puli4b639a22019-10-01 18:12:59 +0530160 {
Vikram Bodireddy3c6c8c32019-12-05 11:06:15 +0530161 // TO-DO: Need to update once CPLD supported Firmware is available
AppaRao Puli4b639a22019-10-01 18:12:59 +0530162 return readVersionFromCPLD(cpldROTVersion, cpldROTSvn);
163 }
164 case (ImageType::biosActive):
165 {
166 return readVersionFromCPLD(pchActiveMajorVersion,
167 pchActiveMinorVersion);
168 }
169 case (ImageType::biosRecovery):
170 {
171 return readVersionFromCPLD(pchRecoveryMajorVersion,
172 pchRecoveryMinorVersion);
173 }
174 case (ImageType::bmcActive):
175 case (ImageType::bmcRecovery):
176 {
177 return readBMCVersionFromSPI(imgType);
178 }
179 default:
180 // Invalid image Type.
181 return "";
182 }
183}
184
AppaRao Pulic532f552019-07-05 15:23:50 +0530185int getProvisioningStatus(bool& ufmLocked, bool& ufmProvisioned)
186{
187 try
188 {
189 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
190 uint8_t provStatus = cpldDev.i2cReadByteData(provisioningStatus);
191 ufmLocked = (provStatus & ufmLockedMask);
192 ufmProvisioned = (provStatus & ufmProvisionedMask);
193 return 0;
194 }
195 catch (const std::exception& e)
196 {
197 phosphor::logging::log<phosphor::logging::level::ERR>(
198 "Exception caught in getProvisioningStatus.",
199 phosphor::logging::entry("MSG=%s", e.what()));
200 return -1;
201 }
202}
203
AppaRao Pulidbe184d2019-10-09 18:04:22 +0530204int readCpldReg(const ActionType& action, uint8_t& value)
AppaRao Puli88aa33b2019-07-18 23:49:55 +0530205{
206 uint8_t cpldReg;
207
208 switch (action)
209 {
210 case (ActionType::recoveryCount):
211 cpldReg = recoveryCount;
212 break;
213 case (ActionType::recoveryReason):
214 cpldReg = lastRecoveryReason;
215 break;
216 case (ActionType::panicCount):
217 cpldReg = panicEventCount;
218 break;
219 case (ActionType::panicReason):
220 cpldReg = panicEventReason;
221 break;
222 case (ActionType::majorError):
223 cpldReg = majorErrorCode;
224 break;
225 case (ActionType::minorError):
226 cpldReg = minorErrorCode;
227 break;
228
229 default:
230 phosphor::logging::log<phosphor::logging::level::ERR>(
231 "Invalid CPLD read action.");
232 return -1;
233 }
234
235 try
236 {
237 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
238 value = cpldDev.i2cReadByteData(cpldReg);
239 return 0;
240 }
241 catch (const std::exception& e)
242 {
243 phosphor::logging::log<phosphor::logging::level::ERR>(
244 "Exception caught in readCpldReg.",
245 phosphor::logging::entry("MSG=%s", e.what()));
246 return -1;
247 }
248}
249
AppaRao Puli46cead92019-07-22 16:50:09 +0530250int setBMCBootCheckpoint(const uint8_t checkPoint)
251{
252 try
253 {
254 I2CFile cpldDev(i2cBusNumber, i2cSlaveAddress, O_RDWR | O_CLOEXEC);
255 cpldDev.i2cWriteByteData(bmcBootCheckpoint, checkPoint);
256 return 0;
257 }
258 catch (const std::exception& e)
259 {
260 phosphor::logging::log<phosphor::logging::level::ERR>(
261 "Exception caught in setBMCBootCheckout.",
262 phosphor::logging::entry("MSG=%s", e.what()));
263 return -1;
264 }
265}
266
AppaRao Pulic532f552019-07-05 15:23:50 +0530267} // namespace pfr
268} // namespace intel