diff --git a/tools/intel-gfx-fw-info b/tools/intel-gfx-fw-info
new file mode 100755
index 000000000..77903bbb7
--- /dev/null
+++ b/tools/intel-gfx-fw-info
@@ -0,0 +1,138 @@
+#!/usr/bin/env python3
+# pylint: disable=C0301
+# SPDX-License-Identifier: (GPL-2.0 OR MIT)
+#
+# Copyright (C) 2023 Intel Corporation
+
+import argparse
+import logging
+import sys
+import typing
+
+# struct definition below should match the one from i915
+# (drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h) and xe
+# (drivers/gpu/drm/xe/xe_uc_fw_abi.h).
+#
+# For compatibility reasons with dissect.cstruct python module, the following
+# things are changed from the original kernel definition:
+#
+#       1) #define in the middle of the struct removed: comment them out
+#       2) No anonymous union - not compatible with the
+#          dumpstruct(): give it a name
+
+CDEF = """
+typedef uint32 u32;
+
+struct uc_css_header {
+	u32 module_type;
+	/*
+	 * header_size includes all non-uCode bits, including css_header, rsa
+	 * key, modulus key and exponent data.
+	 */
+	u32 header_size_dw;
+	u32 header_version;
+	u32 module_id;
+	u32 module_vendor;
+	u32 date;
+// #define CSS_DATE_DAY				(0xFF << 0)
+// #define CSS_DATE_MONTH			(0xFF << 8)
+// #define CSS_DATE_YEAR			(0xFFFF << 16)
+	u32 size_dw; /* uCode plus header_size_dw */
+	u32 key_size_dw;
+	u32 modulus_size_dw;
+	u32 exponent_size_dw;
+	u32 time;
+// #define CSS_TIME_HOUR			(0xFF << 0)
+// #define CSS_DATE_MIN				(0xFF << 8)
+// #define CSS_DATE_SEC				(0xFFFF << 16)
+	char username[8];
+	char buildnumber[12];
+	u32 sw_version;
+// #define CSS_SW_VERSION_UC_MAJOR		(0xFF << 16)
+// #define CSS_SW_VERSION_UC_MINOR		(0xFF << 8)
+// #define CSS_SW_VERSION_UC_PATCH		(0xFF << 0)
+	u32 vf_version;
+	u32 reserved0[12];
+	union {
+		u32 private_data_size; /* only applies to GuC */
+		u32 reserved1;
+	} rsvd;
+	u32 header_info;
+};
+"""
+
+logging.basicConfig(format="%(levelname)s: %(message)s")
+
+try:
+    from dissect import cstruct
+except:
+    logging.critical(
+        "Could not import dissect.cstruct module. See https://github.com/fox-it/dissect.cstruct for installation options"
+    )
+    raise SystemExit(1)
+
+
+def ffs(x: int) -> int:
+    """Returns the index, counting from 0, of the
+    least significant set bit in `x`.
+    """
+    return (x & -x).bit_length() - 1
+
+
+def FIELD_GET(mask: int, value: int) -> int:
+    return (value & mask) >> ffs(mask)
+
+
+def decode(fw) -> str:
+    data = []
+
+    CSS_SW_VERSION_UC_MAJOR = 0xFF << 16
+    CSS_SW_VERSION_UC_MINOR = 0xFF << 8
+    CSS_SW_VERSION_UC_PATCH = 0xFF
+    major = FIELD_GET(CSS_SW_VERSION_UC_MAJOR, fw.sw_version)
+    minor = FIELD_GET(CSS_SW_VERSION_UC_MINOR, fw.sw_version)
+    patch = FIELD_GET(CSS_SW_VERSION_UC_PATCH, fw.sw_version)
+    data += [f"version: {major}.{minor}.{patch}"]
+
+    CSS_DATE_DAY = 0xFF
+    CSS_DATE_MONTH = 0xFF << 8
+    CSS_DATE_YEAR = 0xFFFF << 16
+    day = FIELD_GET(CSS_DATE_DAY, fw.date)
+    month = FIELD_GET(CSS_DATE_MONTH, fw.date)
+    year = FIELD_GET(CSS_DATE_YEAR, fw.date)
+    data += [f"date: {year:02x}-{month:02x}-{day:02x}"]
+
+    return data
+
+
+def parse_args(argv: typing.List[str]) -> argparse.Namespace:
+    description = "Dump GuC/HuC firmware header"
+    parser = argparse.ArgumentParser(prog="intel-gfx-fw-info", description=description)
+
+    parser.add_argument("filename", help="GuC/HuC firmware file")
+
+    return parser.parse_args(argv)
+
+
+def main(argv: typing.List[str]) -> int:
+    args = parse_args(argv)
+
+    cparser = cstruct.cstruct()
+    cparser.load(CDEF)
+
+    try:
+        with open(args.filename, mode="rb") as f:
+            fw = cparser.uc_css_header(f)
+    except FileNotFoundError as e:
+        logging.fatal(e)
+        return 1
+
+    print(*decode(fw), sep="\n")
+    print("raw dump:", end="")
+    cstruct.dumpstruct(fw, color=sys.stdout.isatty())
+
+    return 0
+
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv[1:]))
diff --git a/tools/meson.build b/tools/meson.build
index 4c45f16b9..88c58adfe 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -81,7 +81,7 @@ executable('intel_reg', sources : intel_reg_src,
 	     '-DIGT_DATADIR="@0@"'.format(join_paths(prefix, datadir)),
 	   ])
 
-install_data('intel_gpu_abrt', install_dir : bindir)
+install_data(['intel_gpu_abrt', 'intel-gfx-fw-info'], install_dir : bindir)
 
 install_subdir('registers', install_dir : datadir)
 
