firmware fd: Add PLDM Control version/commands

Supported PLDM firmware (type 5) commands are registered with the PLDM
control responder.

Change-Id: I6a4840a820bf2a1a7967ab9fe927f69681f375d8
Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
diff --git a/src/firmware_device/fd.c b/src/firmware_device/fd.c
index 116657c..f65cfcd 100644
--- a/src/firmware_device/fd.c
+++ b/src/firmware_device/fd.c
@@ -22,6 +22,33 @@
 static const uint8_t INSTANCE_ID_COUNT = 32;
 static const uint8_t PROGRESS_PERCENT_NOT_SUPPORTED = 101;
 
+#define PLDM_FD_VERSIONS_COUNT 2
+static const uint32_t PLDM_FD_VERSIONS[PLDM_FD_VERSIONS_COUNT] = {
+	/* Only PLDM Firmware 1.1.0 is current implemented. */
+	0xf1f1f000,
+	/* CRC. Calculated with python:
+	hex(crccheck.crc.Crc32.calc(struct.pack('<I', 0xf1f1f000)))
+	*/
+	0x539dbeba,
+};
+const bitfield8_t PLDM_FD_COMMANDS[32] = {
+	// 0x00..0x07
+	{ .byte = (1 << PLDM_QUERY_DEVICE_IDENTIFIERS |
+		   1 << PLDM_GET_FIRMWARE_PARAMETERS) },
+	{ 0 },
+	// 0x10..0x17
+	{ .byte = (1u << PLDM_REQUEST_UPDATE | 1u << PLDM_PASS_COMPONENT_TABLE |
+		   1u << PLDM_UPDATE_COMPONENT) >>
+		  0x10 },
+	// 0x18..0x1f
+	{
+		.byte = (1u << PLDM_ACTIVATE_FIRMWARE | 1u << PLDM_GET_STATUS |
+			 1u << PLDM_CANCEL_UPDATE_COMPONENT |
+			 1u << PLDM_CANCEL_UPDATE) >>
+			0x18,
+	},
+};
+
 /* Ensure that public definition is kept updated */
 static_assert(alignof(struct pldm_fd) == PLDM_ALIGNOF_PLDM_FD,
 	      "PLDM_ALIGNOF_PLDM_FD wrong");
@@ -1174,11 +1201,13 @@
 }
 
 LIBPLDM_ABI_TESTING
-struct pldm_fd *pldm_fd_new(const struct pldm_fd_ops *ops, void *ops_ctx)
+struct pldm_fd *pldm_fd_new(const struct pldm_fd_ops *ops, void *ops_ctx,
+			    struct pldm_control *control)
 {
 	struct pldm_fd *fd = malloc(sizeof(*fd));
 	if (fd) {
-		if (pldm_fd_setup(fd, sizeof(*fd), ops, ops_ctx) == 0) {
+		if (pldm_fd_setup(fd, sizeof(*fd), ops, ops_ctx, control) ==
+		    0) {
 			return fd;
 		}
 		free(fd);
@@ -1189,8 +1218,11 @@
 
 LIBPLDM_ABI_TESTING
 int pldm_fd_setup(struct pldm_fd *fd, size_t pldm_fd_size,
-		  const struct pldm_fd_ops *ops, void *ops_ctx)
+		  const struct pldm_fd_ops *ops, void *ops_ctx,
+		  struct pldm_control *control)
 {
+	int rc;
+
 	if (fd == NULL || ops == NULL) {
 		return -EINVAL;
 	}
@@ -1214,6 +1246,16 @@
 	fd->fd_t1_timeout = DEFAULT_FD_T1_TIMEOUT;
 	fd->fd_t2_retry_time = DEFAULT_FD_T2_RETRY_TIME;
 
+	if (control) {
+		rc = pldm_control_add_type(control, PLDM_FWUP,
+					   &PLDM_FD_VERSIONS,
+					   PLDM_FD_VERSIONS_COUNT,
+					   PLDM_FD_COMMANDS);
+		if (rc) {
+			return rc;
+		}
+	}
+
 	return 0;
 }
 
@@ -1297,7 +1339,8 @@
 		break;
 	}
 
-	/* Dispatch command */
+	/* Dispatch command.
+	 Update PLDM_FD_COMMANDS if adding new handlers */
 	switch (hdr.command) {
 	case PLDM_QUERY_DEVICE_IDENTIFIERS:
 		rc = pldm_fd_qdi(fd, &hdr, req, req_payload_len, resp,