On Thu Aug 27 15:33:07 2026 +0300, Antti Laakso wrote:
> The firmware format differs slightly between ipu6 and ipu7.
> Add support for ipu7 firmware validation and handling.
> 
> Signed-off-by: Antti Laakso <[email protected]>
> [Sakari Ailus: Use ipu6_ prefix for ipu7 related global symbols.]
> Signed-off-by: Sakari Ailus <[email protected]>

Patch committed.

Thanks,
Sakari Ailus

 drivers/media/pci/intel/ipu6/ipu6-cpd.c | 169 +++++++++++++++++++++++++++++---
 drivers/media/pci/intel/ipu6/ipu6-cpd.h |  43 ++++++++
 2 files changed, 197 insertions(+), 15 deletions(-)

---

diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c 
b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
index 966a16a300f8..c4b2d954a9d4 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
@@ -16,6 +16,7 @@
 #include "ipu6-bus.h"
 #include "ipu6-cpd.h"
 #include "ipu6-dma.h"
+#include "ipu7-mmu-hw.h"
 
 /* 15 entries + header*/
 #define MAX_PKG_DIR_ENT_CNT            16
@@ -62,6 +63,20 @@ static inline const struct ipu6_cpd_ent 
*ipu6_cpd_get_entry(const void *cpd,
 #define ipu6_cpd_get_metadata(cpd) ipu6_cpd_get_entry(cpd, METADATA_IDX)
 #define ipu6_cpd_get_moduledata(cpd) ipu6_cpd_get_entry(cpd, MODULEDATA_IDX)
 
+#define IPU7_CPD_BINARY_START_IDX      1U
+#define IPU7_CPD_METADATA_START_IDX    2U
+#define IPU7_CPD_BINARY_NUM            2U /* ISYS + PSYS */
+#define IPU7_CPD_METADATA_ATTR         0xa
+#define IPU7_CPD_METADATA_IPL          0x1c
+/*
+ * Entries include:
+ * 1 manifest entry.
+ * 1 metadata entry for each sub system(ISYS and PSYS).
+ * 1 binary entry for each sub system(ISYS and PSYS).
+ */
+#define IPU7_CPD_ENTRY_NUM     (IPU7_CPD_BINARY_NUM * 2U + 1U)
+#define IPU7_MAX_MANIFEST_SIZE (SZ_4K * sizeof(u32))
+
 static const struct ipu6_cpd_metadata_cmpnt_hdr *
 ipu6_cpd_metadata_get_cmpnt(struct ipu6_device *isp, const void *metadata,
                            unsigned int metadata_size, u8 idx)
@@ -309,39 +324,163 @@ static int ipu6_cpd_validate_metadata(struct ipu6_device 
*isp,
        return 0;
 }
 
-int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
-                              unsigned long cpd_file_size)
+static struct ipu7_cpd_metadata *ipu7_cpd_get_metadata(const void *cpd, int 
idx)
 {
-       const struct ipu6_cpd_hdr *hdr = cpd_file;
-       const struct ipu6_cpd_ent *ent;
-       int ret;
+       const struct ipu6_cpd_ent *cpd_ent =
+               ipu6_cpd_get_entry(cpd, IPU7_CPD_METADATA_START_IDX + idx * 2);
 
-       ret = ipu6_cpd_validate_cpd(isp, cpd_file, cpd_file_size,
-                                   cpd_file_size);
-       if (ret)
-               return ret;
+       return (struct ipu7_cpd_metadata *)((u8 *)cpd + cpd_ent->offset);
+}
 
-       /* Check for CPD file marker */
-       if (hdr->hdr_mark != CPD_HDR_MARK) {
-               dev_err(&isp->pdev->dev, "Invalid CPD header\n");
+static int ipu7_cpd_validate_metadata(struct ipu6_device *isp,
+                                     const void *cpd, int idx)
+{
+       const struct ipu6_cpd_ent *cpd_ent =
+               ipu6_cpd_get_entry(cpd, IPU7_CPD_METADATA_START_IDX + idx * 2);
+       const struct ipu6_cpd_ent *bin_ent =
+               ipu6_cpd_get_entry(cpd, IPU7_CPD_BINARY_START_IDX + idx * 2);
+       const struct ipu7_cpd_metadata *metadata =
+               ipu7_cpd_get_metadata(cpd, idx);
+       struct device *dev = &isp->pdev->dev;
+       u32 offset;
+
+       /* Sanity check for metadata size */
+       if (cpd_ent->len != sizeof(struct ipu7_cpd_metadata)) {
+               dev_err(dev, "Invalid metadata size\n");
+               return -EINVAL;
+       }
+
+       /* Validate type and length of metadata sections */
+       if (metadata->attr.hdr.type != IPU7_CPD_METADATA_ATTR) {
+               dev_err(dev, "Invalid metadata attr type (%d)\n",
+                       metadata->attr.hdr.type);
                return -EINVAL;
        }
+       if (metadata->attr.hdr.len != sizeof(struct ipu7_cpd_metadata_attr)) {
+               dev_err(dev, "Invalid metadata attr size (%d)\n",
+                       metadata->attr.hdr.len);
+               return -EINVAL;
+       }
+       if (metadata->ipl.hdr.type != IPU7_CPD_METADATA_IPL) {
+               dev_err(dev, "Invalid metadata ipl type (%d)\n",
+                       metadata->ipl.hdr.type);
+               return -EINVAL;
+       }
+       if (metadata->ipl.hdr.len != sizeof(struct ipu7_cpd_metadata_ipl)) {
+               dev_err(dev, "Invalid metadata ipl size (%d)\n",
+                       metadata->ipl.hdr.len);
+               return -EINVAL;
+       }
+
+       offset = metadata->ipl.param[0];
+       if (offset > IPU7_FW_CODE_REGION_SIZE ||
+           bin_ent->len > IPU7_FW_CODE_REGION_SIZE - offset) {
+               dev_err(dev, "Incorrect binary size %u and offset %u\n",
+                       bin_ent->len, offset);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int __ipu7_validate_cpd_file(struct ipu6_device *isp, const void 
*cpd_file,
+                                   unsigned long cpd_file_size)
+{
+       const struct ipu6_cpd_ent *ent;
+       const struct ipu7_cpd_hdr *hdr = cpd_file;
+       unsigned int i;
 
-       /* Sanity check for manifest size */
        ent = ipu6_cpd_get_manifest(cpd_file);
-       if (ent->len > MAX_MANIFEST_SIZE) {
+       if (ent->len > IPU7_MAX_MANIFEST_SIZE) {
                dev_err(&isp->pdev->dev, "Invalid CPD manifest size\n");
                return -EINVAL;
        }
+       /* Sanity check for CPD entry header */
+       if (hdr->ent_cnt != IPU7_CPD_ENTRY_NUM) {
+               dev_err(&isp->pdev->dev, "Invalid CPD entry number %d\n",
+                       hdr->ent_cnt);
+               return -EINVAL;
+       }
 
        /* Validate metadata */
+       for (i = 0; i < IPU7_CPD_BINARY_NUM; i++) {
+               int ret = ipu7_cpd_validate_metadata(isp, cpd_file, i);
+
+               if (ret) {
+                       dev_err(&isp->pdev->dev, "Invalid metadata(%d)\n", i);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int __ipu6_validate_cpd_file(struct ipu6_device *isp, const void 
*cpd_file,
+                                   unsigned long cpd_file_size)
+{
+       const struct ipu6_cpd_ent *ent;
+       int ret;
+
+       ent = ipu6_cpd_get_manifest(cpd_file);
+       if (ent->len > MAX_MANIFEST_SIZE) {
+               dev_err(&isp->pdev->dev, "Invalid CPD manifest size\n");
+               return -EINVAL;
+       }
+
        ent = ipu6_cpd_get_metadata(cpd_file);
        ret = ipu6_cpd_validate_metadata(isp, cpd_file + ent->offset, ent->len);
        if (ret)
                return ret;
 
-       /* Validate moduledata */
        ent = ipu6_cpd_get_moduledata(cpd_file);
        return ipu6_cpd_validate_moduledata(isp, cpd_file + ent->offset,
                                            ent->len);
 }
+
+int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
+                              unsigned long cpd_file_size)
+{
+       const struct ipu6_cpd_hdr *hdr = cpd_file;
+       int ret;
+
+       ret = ipu6_cpd_validate_cpd(isp, cpd_file, cpd_file_size,
+                                   cpd_file_size);
+       if (ret)
+               return ret;
+
+       /* Check for CPD file marker */
+       if (hdr->hdr_mark != CPD_HDR_MARK) {
+               dev_err(&isp->pdev->dev, "Invalid CPD header\n");
+               return -EINVAL;
+       }
+
+       if (IS_IPU7(isp))
+               return __ipu7_validate_cpd_file(isp, cpd_file, cpd_file_size);
+
+       return __ipu6_validate_cpd_file(isp, cpd_file, cpd_file_size);
+}
+
+int ipu6_ipu7_cpd_copy_binary(const void *cpd, const char *name, void *dst,
+                             u32 *entry)
+{
+       unsigned int i;
+
+       for (i = 0; i < IPU7_CPD_BINARY_NUM; i++) {
+               const struct ipu7_cpd_metadata *metadata;
+               u8 idx = IPU7_CPD_BINARY_START_IDX + i * 2U;
+               const struct ipu6_cpd_ent *ent =
+                       ipu6_cpd_get_entry(cpd, idx);
+
+               if (strncmp(ent->name, name, sizeof(ent->name)))
+                       continue;
+
+               metadata = ipu7_cpd_get_metadata(cpd, i);
+               memcpy(dst + metadata->ipl.param[0], cpd + ent->offset,
+                      ent->len);
+               *entry = metadata->ipl.param[2];
+
+               return 0;
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL_NS_GPL(ipu6_ipu7_cpd_copy_binary, "INTEL_IPU6");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.h 
b/drivers/media/pci/intel/ipu6/ipu6-cpd.h
index e0e4fdeca902..c3a4859d8e79 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.h
@@ -98,8 +98,51 @@ struct ipu6_cpd_client_pkg_hdr {
        u32 prog_bin_size;
 } __packed;
 
+/* IPU7 */
+
+struct ipu7_cpd_hdr {
+       u32 hdr_mark;
+       u32 ent_cnt;
+       u8 hdr_ver;
+       u8 ent_ver;
+       u8 hdr_len;
+       u8 rsvd;
+       u8 partition_name[4];
+       u32 crc32;
+} __packed;
+
+struct ipu7_cpd_metadata_hdr {
+       u32 type;
+       u32 len;
+} __packed;
+
+struct ipu7_cpd_metadata_attr {
+       struct ipu7_cpd_metadata_hdr hdr;
+       u8 compression_type;
+       u8 encryption_type;
+       u8 rsvd[2];
+       u32 uncompressed_size;
+       u32 compressed_size;
+       u32 module_id;
+       u8 hash[48];
+} __packed;
+
+struct ipu7_cpd_metadata_ipl {
+       struct ipu7_cpd_metadata_hdr hdr;
+       u32 param[4];
+       u8 rsvd[8];
+} __packed;
+
+struct ipu7_cpd_metadata {
+       struct ipu7_cpd_metadata_attr attr;
+       struct ipu7_cpd_metadata_ipl ipl;
+} __packed;
+
 int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src);
 void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev);
 int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
                               unsigned long cpd_file_size);
+int ipu6_ipu7_cpd_copy_binary(const void *cpd, const char *name, void *dst,
+                             u32 *entry);
+
 #endif /* IPU6_CPD_H */
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to