i2c-vr: add support for MPS MP292X VR firmware update over I2C
This commit introduces support for programming MPS MP292X VR devices
over the I2C bus. It enables firmware updates for VR models such as
MP2925 and MP2929.
Support for the MP292XFirmware type in EM was added in [1].
[1] https://gerrit.openbmc.org/c/openbmc/entity-manager/+/85159
Tested on the Yosemite5 platform:
1. Display the fw inventory
```
curl --silent $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory
```
```
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory",
"@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection",
"Members": [
{...},
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_1427"
},
{...}
],
"Members@odata.count": 16,
"Name": "Software Inventory Collection"
}
```
2. Query version.
```
curl $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_1427
```
```
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_1427",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Other image",
"Id": "Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_1427",
"Name": "Software Inventory",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Updateable": true,
"Version": "7F652B8C"
}
```
3. Trigger the fw update via redfish.
```
curl -k ${creds} \
-H "Content-Type:multipart/form-data" \
-X POST \
-F UpdateParameters="{\"Targets\":[\"/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_1427\"],\"@Redfish.OperationApplyTime\":\"OnReset\"};type=application/json" \
-F "UpdateFile=@${fwpath};type=application/octet-stream" \
https://${bmc}/redfish/v1/UpdateService/update-multipart
```
4. Task is returned
```
{
"@odata.id": "/redfish/v1/TaskService/Tasks/0",
"@odata.type": "#Task.v1_4_3.Task",
"HidePayload": false,
"Id": "0",
"Messages": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The task with Id '0' has started.",
"MessageArgs": [
"0"
],
"MessageId": "TaskEvent.1.0.TaskStarted",
"MessageSeverity": "OK",
"Resolution": "None."
}
],
"Name": "Task 0",
"Payload": {
"HttpHeaders": [],
"HttpOperation": "POST",
"TargetUri": "/redfish/v1/UpdateService/update-multipart"
},
"PercentComplete": 0,
"StartTime": "2025-11-12T07:19:57+00:00",
"TaskMonitor": "/redfish/v1/TaskService/TaskMonitors/0",
"TaskState": "Running",
"TaskStatus": "OK"
}
```
5. Query Task status
```
curl --silent $creds https://$bmc/redfish/v1/TaskService/Tasks/0
```
```
{
"@odata.id": "/redfish/v1/TaskService/Tasks/0",
"@odata.type": "#Task.v1_4_3.Task",
"EndTime": "2025-11-12T07:20:31+00:00",
"HidePayload": false,
"Id": "0",
"Messages": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The task with Id '0' has started.",
"MessageArgs": [
"0"
],
"MessageId": "TaskEvent.1.0.TaskStarted",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The task with Id '0' has changed to progress 50 percent complete.",
"MessageArgs": [
"0",
"50"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The task with Id '0' has changed to progress 100 percent complete.",
"MessageArgs": [
"0",
"100"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The task with Id '0' has completed.",
"MessageArgs": [
"0"
],
"MessageId": "TaskEvent.1.0.TaskCompletedOK",
"MessageSeverity": "OK",
"Resolution": "None."
}
],
"Name": "Task 0",
"Payload": {
"HttpHeaders": [],
"HttpOperation": "POST",
"JsonBody": "null",
"TargetUri": "/redfish/v1/UpdateService/update-multipart"
},
"PercentComplete": 100,
"StartTime": "2025-11-12T07:19:57+00:00",
"TaskMonitor": "/redfish/v1/TaskService/TaskMonitors/0",
"TaskState": "Completed",
"TaskStatus": "OK"
}
```
6. Display the fw inventory with newly updated fw.
```
curl --silent $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory
```
```
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory",
"@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection",
"Members": [
{...},
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_1427"
},
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_8152"
},
{...}
],
"Members@odata.count": 17,
"Name": "Software Inventory Collection"
}
```
7. Query the new fw version.
```
curl $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_8152
```
```
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_8152",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Other image",
"Id": "Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_8152",
"Name": "Software Inventory",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Updateable": false,
"Version": "7F6588DF"
}
```
8. Do AC cycle to make sure the new fw is applied.
```
busctl set-property xyz.openbmc_project.State.Chassis0 /xyz/openbmc_project/state/chassis0 \
xyz.openbmc_project.State.Chassis RequestedPowerTransition s xyz.openbmc_project.State.Chassis.Transition.PowerCycle
```
9. Display the fw inventory after AC cycle.
```
curl --silent $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory
```
```
kevin@meta-device:~$ curl --silent $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory",
"@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection",
"Members": [
{...},
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_8379"
},
{...}
],
"Members@odata.count": 16,
"Name": "Software Inventory Collection"
}
```
10. Query the fw version after AC cycle.
```
curl $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_8379
```
```
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_8379",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Other image",
"Id": "Yosemite5_CXL_VR_P1V2_VDD_DDR_CH13_8379",
"Name": "Software Inventory",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Updateable": true,
"Version": "7F6588DF"
}
```
Change-Id: I261a3b9619154860e0a636a633247965fea11032
Signed-off-by: Kevin Tung <kevin.tung.openbmc@gmail.com>
diff --git a/i2c-vr/i2cvr_software_manager.cpp b/i2c-vr/i2cvr_software_manager.cpp
index 43c77b9..61a52b9 100644
--- a/i2c-vr/i2cvr_software_manager.cpp
+++ b/i2c-vr/i2cvr_software_manager.cpp
@@ -21,9 +21,10 @@
const std::string configDBusName = "I2CVR";
const std::vector<std::string> emConfigTypes = {
- "XDPE1X2XXFirmware", "ISL69269Firmware", "MP2X6XXFirmware",
- "MP297XFirmware", "MP5998Firmware", "MP994XFirmware",
- "RAA22XGen2Firmware", "RAA22XGen3p5Firmware", "TDA38640AFirmware"};
+ "XDPE1X2XXFirmware", "ISL69269Firmware", "MP2X6XXFirmware",
+ "MP292XFirmware", "MP297XFirmware", "MP5998Firmware",
+ "MP994XFirmware", "RAA22XGen2Firmware", "RAA22XGen3p5Firmware",
+ "TDA38640AFirmware"};
I2CVRSoftwareManager::I2CVRSoftwareManager(sdbusplus::async::context& ctx) :
ManagerInf::SoftwareManager(ctx, configDBusName)
diff --git a/i2c-vr/meson.build b/i2c-vr/meson.build
index b21eff3..97f0679 100644
--- a/i2c-vr/meson.build
+++ b/i2c-vr/meson.build
@@ -5,8 +5,8 @@
'mps/mp297x.cpp',
'mps/mp2x6xx.cpp',
'mps/mp5998.cpp',
- 'mps/mp994x.cpp',
'mps/mps.cpp',
+ 'mps/mpx9xx.cpp',
'tda38640a/tda38640a.cpp',
'xdpe1x2xx/xdpe1x2xx.cpp',
)
diff --git a/i2c-vr/mps/mp994x.hpp b/i2c-vr/mps/mp994x.hpp
deleted file mode 100644
index a729aa2..0000000
--- a/i2c-vr/mps/mp994x.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include "common/include/pmbus.hpp"
-#include "mps.hpp"
-
-namespace phosphor::software::VR
-{
-
-enum class MP994XCmd : uint8_t;
-
-class MP994X : public MPSVoltageRegulator
-{
- public:
- MP994X(sdbusplus::async::context& ctx, uint16_t bus, uint16_t address) :
- MPSVoltageRegulator(ctx, bus, address)
- {}
-
- sdbusplus::async::task<bool> verifyImage(const uint8_t* image,
- size_t imageSize) final;
- sdbusplus::async::task<bool> updateFirmware(bool force) final;
- sdbusplus::async::task<bool> getCRC(uint32_t* checksum) final;
- sdbusplus::async::task<bool> parseDeviceConfiguration() final;
- bool forcedUpdateAllowed() final;
-
- private:
- sdbusplus::async::task<bool> checkId(MP994XCmd idCmd, uint32_t expected);
- sdbusplus::async::task<bool> unlockWriteProtect();
- sdbusplus::async::task<bool> disableStoreFaultTriggering();
- sdbusplus::async::task<bool> setMultiConfigAddress(uint8_t config);
- sdbusplus::async::task<bool> programConfigData(
- const std::vector<MPSData>& gdata);
- sdbusplus::async::task<bool> programAllRegisters();
- sdbusplus::async::task<bool> storeDataIntoMTP();
- sdbusplus::async::task<bool> restoreDataFromNVM();
- sdbusplus::async::task<bool> checkMTPCRC();
-};
-
-} // namespace phosphor::software::VR
diff --git a/i2c-vr/mps/mps.hpp b/i2c-vr/mps/mps.hpp
index 25aa9ec..07cac2b 100644
--- a/i2c-vr/mps/mps.hpp
+++ b/i2c-vr/mps/mps.hpp
@@ -68,7 +68,7 @@
uint8_t page = 0;
uint8_t addr = 0;
uint8_t length = 0;
- std::array<uint8_t, 4> data{};
+ std::array<uint8_t, 8> data{};
};
struct MPSConfig
diff --git a/i2c-vr/mps/mp994x.cpp b/i2c-vr/mps/mpx9xx.cpp
similarity index 86%
rename from i2c-vr/mps/mp994x.cpp
rename to i2c-vr/mps/mpx9xx.cpp
index 6342001..2dabada 100644
--- a/i2c-vr/mps/mp994x.cpp
+++ b/i2c-vr/mps/mpx9xx.cpp
@@ -1,4 +1,4 @@
-#include "mp994x.hpp"
+#include "mpx9xx.hpp"
#include "common/include/utils.hpp"
@@ -15,15 +15,16 @@
static constexpr uint8_t pageMask = 0x0F;
-enum class MP994XCmd : uint8_t
+enum class MPX9XXCmd : uint8_t
{
// Page 0 commands
storeUserAll = 0x15,
userData08 = 0xB8,
// Page 2 commands
+ configIdMP292X = 0xA9,
mfrMulconfigSel = 0xAB,
- configId = 0xAF,
+ configIdMP994X = 0xAF,
mfrNVMPmbusCtrl = 0xCA,
mfrDebug = 0xD4,
deviceId = 0xDB,
@@ -35,7 +36,17 @@
storeFaultTrigger = 0x51,
};
-sdbusplus::async::task<bool> MP994X::parseDeviceConfiguration()
+MPX9XXCmd MP292X::getConfigIdCmd() const
+{
+ return MPX9XXCmd::configIdMP292X;
+}
+
+MPX9XXCmd MP994X::getConfigIdCmd() const
+{
+ return MPX9XXCmd::configIdMP994X;
+}
+
+sdbusplus::async::task<bool> MPX9XX::parseDeviceConfiguration()
{
if (!configuration)
{
@@ -75,7 +86,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::verifyImage(const uint8_t* image,
+sdbusplus::async::task<bool> MPX9XX::verifyImage(const uint8_t* image,
size_t imageSize)
{
if (!co_await parseImage(image, imageSize, MPSImageType::type1))
@@ -101,7 +112,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::checkId(MP994XCmd idCmd, uint32_t expected)
+sdbusplus::async::task<bool> MPX9XX::checkId(MPX9XXCmd idCmd, uint32_t expected)
{
static constexpr size_t vendorIdLength = 2;
static constexpr size_t productIdLength = 1;
@@ -113,15 +124,16 @@
switch (idCmd)
{
- case MP994XCmd::vendorId:
+ case MPX9XXCmd::vendorId:
page = MPSPage::page5;
idLen = vendorIdLength;
break;
- case MP994XCmd::deviceId:
+ case MPX9XXCmd::deviceId:
page = MPSPage::page2;
idLen = productIdLength;
break;
- case MP994XCmd::configId:
+ case MPX9XXCmd::configIdMP292X:
+ case MPX9XXCmd::configIdMP994X:
page = MPSPage::page2;
idLen = configIdLength;
break;
@@ -160,7 +172,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::unlockWriteProtect()
+sdbusplus::async::task<bool> MPX9XX::unlockWriteProtect()
{
static constexpr uint8_t unlockWriteProtectData = 0x00;
@@ -185,7 +197,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::disableStoreFaultTriggering()
+sdbusplus::async::task<bool> MPX9XX::disableStoreFaultTriggering()
{
static constexpr size_t mfrDebugDataLength = 2;
static constexpr uint16_t enableEnteringPage7Mask = 0x8000;
@@ -202,7 +214,7 @@
co_return false;
}
- tbuf = buildByteVector(MP994XCmd::mfrDebug);
+ tbuf = buildByteVector(MPX9XXCmd::mfrDebug);
rbuf.resize(mfrDebugDataLength);
if (!i2cInterface.sendReceive(tbuf, rbuf))
{
@@ -211,7 +223,7 @@
}
uint16_t data = (rbuf[1] << 8) | rbuf[0] | enableEnteringPage7Mask;
- tbuf = buildByteVector(MP994XCmd::mfrDebug, data);
+ tbuf = buildByteVector(MPX9XXCmd::mfrDebug, data);
rbuf.clear();
if (!i2cInterface.sendReceive(tbuf, rbuf))
{
@@ -227,7 +239,7 @@
co_return false;
}
- tbuf = buildByteVector(MP994XCmd::storeFaultTrigger,
+ tbuf = buildByteVector(MPX9XXCmd::storeFaultTrigger,
disableStoreFaultTriggeringData);
rbuf.clear();
if (!i2cInterface.sendReceive(tbuf, rbuf))
@@ -241,7 +253,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::setMultiConfigAddress(uint8_t config)
+sdbusplus::async::task<bool> MPX9XX::setMultiConfigAddress(uint8_t config)
{
// MPS994X: Select multi-configuration address
// Write to Page 2 @ 0xAB:
@@ -270,12 +282,12 @@
}
uint8_t selectAddrData = enableMultiConfigAddrSel + addr;
- tbuf = buildByteVector(MP994XCmd::mfrMulconfigSel, selectAddrData);
+ tbuf = buildByteVector(MPX9XXCmd::mfrMulconfigSel, selectAddrData);
if (!i2cInterface.sendReceive(tbuf, rbuf))
{
error("Failed to write {DATA} to multi config select register {REG}",
"DATA", lg2::hex, selectAddrData, "REG", lg2::hex,
- static_cast<uint8_t>(MP994XCmd::mfrMulconfigSel));
+ static_cast<uint8_t>(MPX9XXCmd::mfrMulconfigSel));
co_return false;
}
@@ -283,7 +295,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::programConfigData(
+sdbusplus::async::task<bool> MPX9XX::programConfigData(
const std::vector<MPSData>& gdata)
{
std::vector<uint8_t> tbuf;
@@ -324,7 +336,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::programAllRegisters()
+sdbusplus::async::task<bool> MPX9XX::programAllRegisters()
{
// config 0 = User Registers
// config 1 ~ 8 = Multi-configuration Registers
@@ -355,7 +367,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::storeDataIntoMTP()
+sdbusplus::async::task<bool> MPX9XX::storeDataIntoMTP()
{
std::vector<uint8_t> tbuf;
std::vector<uint8_t> rbuf;
@@ -367,7 +379,7 @@
co_return false;
}
- tbuf = buildByteVector(MP994XCmd::storeUserAll);
+ tbuf = buildByteVector(MPX9XXCmd::storeUserAll);
if (!i2cInterface.sendReceive(tbuf, rbuf))
{
error("Failed to store data into MTP");
@@ -381,7 +393,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::getCRC(uint32_t* checksum)
+sdbusplus::async::task<bool> MPX9XX::getCRC(uint32_t* checksum)
{
static constexpr size_t crcUserMultiDataLength = 4;
static constexpr size_t statusByteLength = 1;
@@ -396,7 +408,7 @@
co_return false;
}
- tbuf = buildByteVector(MP994XCmd::userData08);
+ tbuf = buildByteVector(MPX9XXCmd::userData08);
rbuf.resize(crcUserMultiDataLength + statusByteLength);
if (!i2cInterface.sendReceive(tbuf, rbuf))
{
@@ -411,7 +423,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::restoreDataFromNVM()
+sdbusplus::async::task<bool> MPX9XX::restoreDataFromNVM()
{
static constexpr size_t nvmPmbusCtrlDataLength = 2;
static constexpr uint16_t enableRestoreDataFromMTPMask = 0x0008;
@@ -427,7 +439,7 @@
co_return false;
}
- tbuf = buildByteVector(MP994XCmd::mfrNVMPmbusCtrl);
+ tbuf = buildByteVector(MPX9XXCmd::mfrNVMPmbusCtrl);
rbuf.resize(nvmPmbusCtrlDataLength);
if (!i2cInterface.sendReceive(tbuf, rbuf))
{
@@ -436,7 +448,7 @@
}
uint16_t data = ((rbuf[1] << 8) | rbuf[0]) | enableRestoreDataFromMTPMask;
- tbuf = buildByteVector(MP994XCmd::mfrNVMPmbusCtrl, data);
+ tbuf = buildByteVector(MPX9XXCmd::mfrNVMPmbusCtrl, data);
rbuf.clear();
if (!i2cInterface.sendReceive(tbuf, rbuf))
{
@@ -466,7 +478,7 @@
co_return true;
}
-sdbusplus::async::task<bool> MP994X::checkMTPCRC()
+sdbusplus::async::task<bool> MPX9XX::checkMTPCRC()
{
uint32_t crc = 0;
// NOLINTBEGIN(clang-analyzer-core.uninitialized.Branch)
@@ -483,12 +495,12 @@
co_return configuration->crcMulti == crc;
}
-bool MP994X::forcedUpdateAllowed()
+bool MPX9XX::forcedUpdateAllowed()
{
return true;
}
-sdbusplus::async::task<bool> MP994X::updateFirmware(bool force)
+sdbusplus::async::task<bool> MPX9XX::updateFirmware(bool force)
{
(void)force;
@@ -498,17 +510,17 @@
co_return false;
}
- if (!co_await checkId(MP994XCmd::vendorId, configuration->vendorId))
+ if (!co_await checkId(MPX9XXCmd::vendorId, configuration->vendorId))
{
co_return false;
}
- if (!co_await checkId(MP994XCmd::deviceId, configuration->productId))
+ if (!co_await checkId(MPX9XXCmd::deviceId, configuration->productId))
{
co_return false;
}
- if (!co_await checkId(MP994XCmd::configId, configuration->configId))
+ if (!co_await checkId(getConfigIdCmd(), configuration->configId))
{
co_return false;
}
diff --git a/i2c-vr/mps/mpx9xx.hpp b/i2c-vr/mps/mpx9xx.hpp
new file mode 100644
index 0000000..3de9b17
--- /dev/null
+++ b/i2c-vr/mps/mpx9xx.hpp
@@ -0,0 +1,67 @@
+#pragma once
+
+#include "common/include/pmbus.hpp"
+#include "mps.hpp"
+
+namespace phosphor::software::VR
+{
+
+enum class MPX9XXCmd : uint8_t;
+
+/**
+ * @class MPX9XX
+ * @brief Base class for MPX9XX voltage regulators
+ *
+ * Provides common firmware update steps such as unlocking write protection,
+ * programming registers, storing/restoring NVM data, and CRC checks.
+ * Derived classes only need to provide the Config ID command.
+ */
+class MPX9XX : public MPSVoltageRegulator
+{
+ public:
+ MPX9XX(sdbusplus::async::context& ctx, uint16_t bus, uint16_t address) :
+ MPSVoltageRegulator(ctx, bus, address)
+ {}
+
+ sdbusplus::async::task<bool> verifyImage(const uint8_t* image,
+ size_t imageSize) final;
+ sdbusplus::async::task<bool> updateFirmware(bool force) final;
+ sdbusplus::async::task<bool> getCRC(uint32_t* checksum) final;
+ sdbusplus::async::task<bool> parseDeviceConfiguration() final;
+ bool forcedUpdateAllowed() final;
+
+ private:
+ sdbusplus::async::task<bool> checkId(MPX9XXCmd idCmd, uint32_t expected);
+ sdbusplus::async::task<bool> unlockWriteProtect();
+ sdbusplus::async::task<bool> disableStoreFaultTriggering();
+ sdbusplus::async::task<bool> setMultiConfigAddress(uint8_t config);
+ sdbusplus::async::task<bool> programConfigData(
+ const std::vector<MPSData>& gdata);
+ sdbusplus::async::task<bool> programAllRegisters();
+ sdbusplus::async::task<bool> storeDataIntoMTP();
+ sdbusplus::async::task<bool> restoreDataFromNVM();
+ sdbusplus::async::task<bool> checkMTPCRC();
+
+ protected:
+ virtual MPX9XXCmd getConfigIdCmd() const = 0;
+};
+
+class MP292X : public MPX9XX
+{
+ public:
+ using MPX9XX::MPX9XX;
+
+ protected:
+ MPX9XXCmd getConfigIdCmd() const final;
+};
+
+class MP994X : public MPX9XX
+{
+ public:
+ using MPX9XX::MPX9XX;
+
+ protected:
+ MPX9XXCmd getConfigIdCmd() const final;
+};
+
+} // namespace phosphor::software::VR
diff --git a/i2c-vr/vr.cpp b/i2c-vr/vr.cpp
index 1178d8f..1e25ab5 100644
--- a/i2c-vr/vr.cpp
+++ b/i2c-vr/vr.cpp
@@ -4,7 +4,7 @@
#include "mps/mp297x.hpp"
#include "mps/mp2x6xx.hpp"
#include "mps/mp5998.hpp"
-#include "mps/mp994x.hpp"
+#include "mps/mpx9xx.hpp"
#include "tda38640a/tda38640a.hpp"
#include "xdpe1x2xx/xdpe1x2xx.hpp"
@@ -25,6 +25,8 @@
return std::make_unique<ISL69269>(ctx, bus, address);
case VRType::MP2X6XX:
return std::make_unique<MP2X6XX>(ctx, bus, address);
+ case VRType::MP292X:
+ return std::make_unique<MP292X>(ctx, bus, address);
case VRType::MP297X:
return std::make_unique<MP297X>(ctx, bus, address);
case VRType::MP5998:
@@ -50,6 +52,7 @@
{"XDPE1X2XXFirmware", VRType::XDPE1X2XX},
{"ISL69269Firmware", VRType::ISL69269},
{"MP2X6XXFirmware", VRType::MP2X6XX},
+ {"MP292XFirmware", VRType::MP292X},
{"MP297XFirmware", VRType::MP297X},
{"MP5998Firmware", VRType::MP5998},
{"MP994XFirmware", VRType::MP994X},
diff --git a/i2c-vr/vr.hpp b/i2c-vr/vr.hpp
index 9aa53f5..3c08304 100644
--- a/i2c-vr/vr.hpp
+++ b/i2c-vr/vr.hpp
@@ -14,6 +14,7 @@
XDPE1X2XX,
ISL69269,
MP2X6XX,
+ MP292X,
MP297X,
MP5998,
MP994X,