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]