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.hpp b/tpm/tpm_device.hpp
new file mode 100644
index 0000000..a6e220e
--- /dev/null
+++ b/tpm/tpm_device.hpp
@@ -0,0 +1,76 @@
+#pragma once
+
+#include "common/include/device.hpp"
+#include "common/include/software_manager.hpp"
+
+#include <sdbusplus/async.hpp>
+
+#include <unordered_map>
+
+namespace SoftwareInf = phosphor::software;
+namespace ManagerInf = SoftwareInf::manager;
+
+enum class TPMType
+{
+    TPM2,
+};
+
+class TPMInterface
+{
+  public:
+    TPMInterface(sdbusplus::async::context& ctx, uint8_t tpmIndex) :
+        ctx(ctx), tpmIndex(tpmIndex)
+    {}
+    virtual ~TPMInterface() = default;
+    TPMInterface(const TPMInterface&) = delete;
+    TPMInterface& operator=(const TPMInterface&) = delete;
+    TPMInterface(TPMInterface&&) = delete;
+    TPMInterface& operator=(TPMInterface&&) = delete;
+
+    virtual bool isUpdateSupported() const = 0;
+    virtual sdbusplus::async::task<bool> getVersion(std::string& version) = 0;
+    virtual sdbusplus::async::task<bool> updateFirmware(const uint8_t* image,
+                                                        size_t imageSize) = 0;
+
+  protected:
+    sdbusplus::async::context& ctx;
+    uint8_t tpmIndex;
+};
+
+class TPMDevice : public Device
+{
+  public:
+    using Device::softwareCurrent;
+
+    TPMDevice(sdbusplus::async::context& ctx, enum TPMType tpmType,
+              uint8_t tpmIndex, SoftwareConfig& config,
+              ManagerInf::SoftwareManager* parent);
+
+    sdbusplus::async::task<bool> updateDevice(const uint8_t* image,
+                                              size_t image_size) final;
+
+    sdbusplus::async::task<std::string> getVersion();
+
+    bool isUpdateSupported() const
+    {
+        return tpmInterface ? tpmInterface->isUpdateSupported() : false;
+    }
+
+  private:
+    std::unique_ptr<TPMInterface> tpmInterface;
+};
+
+inline bool stringToTPMType(const std::string& type, TPMType& tpmType)
+{
+    static const std::unordered_map<std::string, TPMType> tpmTypeMap = {
+        {"TPM2Firmware", TPMType::TPM2},
+    };
+
+    auto it = tpmTypeMap.find(type);
+    if (it != tpmTypeMap.end())
+    {
+        tpmType = it->second;
+        return true;
+    }
+    return false;
+}