i2c-vr: add support for Infineon TDA38640A VR firmware update over I2C
This commit introduces support for programming Infineon TDA38640A VR
devices over the I2C bus. It enables firmware updates for TDA38640A.
Related commit:
EM(Merged):
[1] https://gerrit.openbmc.org/c/openbmc/entity-manager/+/84725
Schema(Merged):
[2] https://gerrit.openbmc.org/c/openbmc/entity-manager/+/84724
PDI(Merged) :
[3] https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/84412
Tested on the Yosemite5 platform.
```
$ target=$(curl -k ${creds} --silent -X GET https://${bmc}/redfish/v1/UpdateService/FirmwareInventory/ | jq -r '.Members[] | select(.["@odata.id"] | contains("MB_VR_PVDD18")) | .["@odata.id"]')
$ curl -k ${creds} -X GET https://${bmc}${target}
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_MB_VR_PVDD18_S5_7939",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Other image",
"Id": "Yosemite5_MB_VR_PVDD18_S5_7939",
"Name": "Software Inventory",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Updateable": true,
"Version": "5E281514"
$ fwpath="/media/leo/data/yv5/mb_vr_sni/yosemite5-mb-vr-pvdd18-s5-B651B567.pldm"
$ curl -k ${creds} \
-H "Content-Type:multipart/form-data" \
-X POST \
-F UpdateParameters="{\"Targets\":[\"${target}\"],\"@Redfish.OperationApplyTime\":\"OnReset\"};type=application/json" \
-F "UpdateFile=@${fwpath};type=application/octet-stream" \
https://${bmc}/redfish/v1/UpdateService/update-multipart
{
"@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-04T06:51:04+00:00",
"TaskMonitor": "/redfish/v1/TaskService/TaskMonitors/0",
"TaskState": "Running",
"TaskStatus": "OK"
}
$
========== ac cycle ==========
$ target=$(curl -k ${creds} --silent -X GET https://${bmc}/redfish/v1/UpdateService/FirmwareInventory/ | jq -r '.Members[] | select(.["@odata.id"] | contains("MB_VR_PVDD18")) | .["@odata.id"]')
$ curl -k ${creds} -X GET https://${bmc}${target}
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_MB_VR_PVDD18_S5_5761",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Other image",
"Id": "Yosemite5_MB_VR_PVDD18_S5_5761",
"Name": "Software Inventory",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Updateable": true,
"Version": "B651B567"
}
```
Change-Id: I69fc2e3b83f56836aceff4e8b24dc85448f7c7ff
Signed-off-by: Leo Yang <Leo-Yang@quantatw.com>
diff --git a/i2c-vr/tda38640a/tda38640a.hpp b/i2c-vr/tda38640a/tda38640a.hpp
new file mode 100644
index 0000000..2488eda
--- /dev/null
+++ b/i2c-vr/tda38640a/tda38640a.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "common/include/i2c/i2c.hpp"
+#include "i2c-vr/vr.hpp"
+
+#include <sdbusplus/async.hpp>
+
+#include <cstdint>
+#include <unordered_set>
+
+namespace phosphor::software::VR
+{
+
+class TDA38640A : public VoltageRegulator
+{
+ public:
+ TDA38640A(sdbusplus::async::context& ctx, uint16_t bus, uint16_t 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;
+
+ bool forcedUpdateAllowed() final;
+
+ private:
+ struct Configuration
+ {
+ uint32_t rev;
+ uint32_t checksum;
+ std::vector<uint16_t> offsets;
+ std::vector<std::vector<uint8_t>> data;
+
+ void clear()
+ {
+ rev = 0;
+ checksum = 0;
+ offsets.clear();
+ data.clear();
+ }
+ };
+
+ sdbusplus::async::task<bool> getUserRemainingWrites(uint8_t* remain);
+ sdbusplus::async::task<bool> getDeviceId(uint32_t* deviceId);
+ sdbusplus::async::task<bool> program();
+ sdbusplus::async::task<bool> getProgStatus(uint8_t* status);
+ sdbusplus::async::task<bool> unlockDevice();
+ sdbusplus::async::task<bool> programmingCmd();
+ sdbusplus::async::task<bool> setPage(uint8_t page);
+ sdbusplus::async::task<bool> getDeviceRevision(uint8_t* revision);
+
+ bool parseImage(const uint8_t* image, size_t imageSize);
+
+ phosphor::i2c::I2C i2cInterface;
+
+ struct Configuration configuration;
+};
+} // namespace phosphor::software::VR