TPM code updater

This commit introduces a TPM code updater that currently supports
reading the firmware version for both Infineon and Nuvoton TPM 2.0.
Support for firmware updates will be introduced in a future patch.

The updater's configuration are managed by the EM [1].
[1] https://gerrit.openbmc.org/c/openbmc/entity-manager/+/82416

Tested on Yosemite5 with the following steps:

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_TPM_4945"
    },
    {...}
  ],
  "Members@odata.count": 4,
  "Name": "Software Inventory Collection"
}
```

2. Query TPM version:
```
curl --silent $creds https://$bmc/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_TPM_4945
{
  "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Yosemite5_TPM_4945",
  "@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
  "Description": "Unknown image",
  "Id": "Yosemite5_TPM_4945",
  "Name": "Software Inventory",
  "Status": {
    "Health": "Warning",
    "HealthRollup": "OK",
    "State": "Disabled"
  },
  "Updateable": false,
  "Version": "15.23"
}
```

Change-Id: I42568242356d55fe005ba1f41ddf8aaf9f682fc8
Signed-off-by: Kevin Tung <kevin.tung.openbmc@gmail.com>
diff --git a/tpm/tpm_device.cpp b/tpm/tpm_device.cpp
new file mode 100644
index 0000000..43f8853
--- /dev/null
+++ b/tpm/tpm_device.cpp
@@ -0,0 +1,66 @@
+#include "tpm_device.hpp"
+
+#include "tpm2/tpm2.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+#include <sdbusplus/async.hpp>
+
+PHOSPHOR_LOG2_USING;
+
+TPMDevice::TPMDevice(sdbusplus::async::context& ctx, enum TPMType tpmType,
+                     uint8_t tpmIndex, SoftwareConfig& config,
+                     ManagerInf::SoftwareManager* parent) :
+    Device(ctx, config, parent, {RequestedApplyTimes::OnReset})
+{
+    switch (tpmType)
+    {
+        case TPMType::TPM2:
+            tpmInterface = std::make_unique<TPM2Interface>(ctx, tpmIndex);
+            break;
+        default:
+            tpmInterface = nullptr;
+            error("Unsupported TPM type: {TYPE}", "TYPE",
+                  static_cast<int>(tpmType));
+            break;
+    }
+}
+
+sdbusplus::async::task<bool> TPMDevice::updateDevice(const uint8_t* image,
+                                                     size_t imageSize)
+{
+    if (tpmInterface == nullptr)
+    {
+        error("TPM interface is not initialized");
+        co_return false;
+    }
+
+    setUpdateProgress(10);
+
+    if (!co_await tpmInterface->updateFirmware(image, imageSize))
+    {
+        error("Failed to update TPM firmware");
+        co_return false;
+    }
+
+    setUpdateProgress(100);
+    debug("Successfully updated TPM");
+    co_return true;
+}
+
+sdbusplus::async::task<std::string> TPMDevice::getVersion()
+{
+    std::string version = "Unknown";
+
+    if (tpmInterface == nullptr)
+    {
+        error("TPM interface is not initialized");
+        co_return version;
+    }
+
+    if (!co_await tpmInterface->getVersion(version))
+    {
+        error("Failed to get TPM version");
+    }
+
+    co_return version;
+}