cpld: add update support for Lattice xo5

Enable firmware update capability for Lattice xo5 devices, allowing
the update flow to recognize and handle this device type.

Test on Santabarbara:
```
1. Check firmware
curl -k -u root:0penBmc -X GET
https://10.10.15.214/redfish/v1/UpdateService/FirmwareInventory/Santabarbara_MB_CPLD_6213
{
  "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Santabarbara_MB_CPLD_6213",
  "@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
  "Description": "Unknown image",
  "Id": "Santabarbara_MB_CPLD_6213",
  "Name": "Software Inventory",
  "Status": {
    "Health": "OK",
    "HealthRollup": "OK",
    "State": "Enabled"
  },
  "Updateable": true,
  "Version": "70000003"
}

2. Trigger Update
curl -k -u root:0penBmc \
  -H "Content-Type:multipart/form-data" \
  -X POST \
  -F UpdateParameters="{\"Targets\":[\"${targetpath}\"], \
  \"@Redfish.OperationApplyTime\":\"Immediate\"};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-08-14T02:26:00+00:00",
  "TaskMonitor": "/redfish/v1/TaskService/TaskMonitors/0",
  "TaskState": "Running",
  "TaskStatus": "OK"
}

3. Check task
curl -u root:0penBmc -k -X GET https://${bmc}/redfish/v1/TaskService/Tasks/0
{
  "@odata.id": "/redfish/v1/TaskService/Tasks/0",
  "@odata.type": "#Task.v1_4_3.Task",
  "EndTime": "2025-08-14T02:28:32+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 1 percent complete.",
      "MessageArgs": [
        "0",
        "1"
      ],
      "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 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 90 percent complete.",
      "MessageArgs": [
        "0",
        "90"
      ],
      "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-08-14T02:26:00+00:00",
  "TaskMonitor": "/redfish/v1/TaskService/TaskMonitors/0",
  "TaskState": "Completed",
  "TaskStatus": "OK"
}

4. Check firmware again
curl -k -u root:0penBmc -X GET
https://10.10.15.214/redfish/v1/UpdateService/FirmwareInventory/Santabarbara_MB_CPLD_9204
{
  "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Santabarbara_MB_CPLD_9204",
  "@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
  "Description": "Unknown image",
  "Id": "Santabarbara_MB_CPLD_9204",
  "Name": "Software Inventory",
  "Status": {
    "Health": "OK",
    "HealthRollup": "OK",
    "State": "Enabled"
  },
  "Updateable": true,
  "Version": "00000004"
}
```

Change-Id: Id0aef0d105138538851f4c6d3a5496ec8b724eea
Signed-off-by: Daniel Hsu <Daniel-Hsu@quantatw.com>
diff --git a/cpld/lattice/lattice_xo5_cpld.hpp b/cpld/lattice/lattice_xo5_cpld.hpp
new file mode 100644
index 0000000..efc301f
--- /dev/null
+++ b/cpld/lattice/lattice_xo5_cpld.hpp
@@ -0,0 +1,39 @@
+#include "lattice_base_cpld.hpp"
+
+namespace phosphor::software::cpld
+{
+
+class LatticeXO5CPLD : public LatticeBaseCPLD
+{
+  public:
+    LatticeXO5CPLD(sdbusplus::async::context& ctx, const uint16_t bus,
+                   const uint8_t address, const std::string& chip,
+                   const std::string& target, const bool debugMode) :
+        LatticeBaseCPLD(ctx, bus, address, chip, target, debugMode)
+    {}
+    ~LatticeXO5CPLD() override = default;
+    LatticeXO5CPLD(const LatticeXO5CPLD&) = delete;
+    LatticeXO5CPLD& operator=(const LatticeXO5CPLD&) = delete;
+    LatticeXO5CPLD(LatticeXO5CPLD&&) noexcept = delete;
+    LatticeXO5CPLD& operator=(LatticeXO5CPLD&&) noexcept = delete;
+
+  protected:
+    sdbusplus::async::task<bool> prepareUpdate(const uint8_t* image,
+                                               size_t imageSize) override;
+    sdbusplus::async::task<bool> doUpdate() override;
+    sdbusplus::async::task<bool> finishUpdate() override;
+    sdbusplus::async::task<bool> readUserCode(uint32_t& userCode) override;
+
+  private:
+    sdbusplus::async::task<bool> waitUntilReady(
+        std::chrono::milliseconds timeout);
+    sdbusplus::async::task<bool> eraseCfg();
+    sdbusplus::async::task<bool> programCfg();
+    sdbusplus::async::task<bool> programPage(uint8_t block, uint8_t page,
+                                             const std::vector<uint8_t>& data);
+    sdbusplus::async::task<bool> verifyCfg();
+    sdbusplus::async::task<bool> readPage(uint8_t block, uint8_t page,
+                                          std::vector<uint8_t>& data);
+};
+
+} // namespace phosphor::software::cpld