i915_vma_resource.o
 
 # general-purpose microcontroller (GuC) support
-i915-y += gt/uc/intel_uc.o \
-         gt/uc/intel_uc_debugfs.o \
-         gt/uc/intel_uc_fw.o \
+i915-y += \
+         gt/uc/intel_gsc_uc.o \
          gt/uc/intel_guc.o \
          gt/uc/intel_guc_ads.o \
          gt/uc/intel_guc_capture.o \
          gt/uc/intel_guc_submission.o \
          gt/uc/intel_huc.o \
          gt/uc/intel_huc_debugfs.o \
-         gt/uc/intel_huc_fw.o
+         gt/uc/intel_huc_fw.o \
+         gt/uc/intel_uc.o \
+         gt/uc/intel_uc_debugfs.o \
+         gt/uc/intel_uc_fw.o
 
 # graphics system controller (GSC) support
 i915-y += gt/intel_gsc.o
 
        return container_of(huc, struct intel_gt, uc.huc);
 }
 
+static inline struct intel_gt *gsc_uc_to_gt(struct intel_gsc_uc *gsc_uc)
+{
+       return container_of(gsc_uc, struct intel_gt, uc.gsc);
+}
+
 static inline struct intel_gt *gsc_to_gt(struct intel_gsc *gsc)
 {
        return container_of(gsc, struct intel_gt, gsc);
 
--- /dev/null
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include <linux/types.h>
+
+#include "gt/intel_gt.h"
+#include "intel_gsc_uc.h"
+#include "i915_drv.h"
+
+static bool gsc_engine_supported(struct intel_gt *gt)
+{
+       intel_engine_mask_t mask;
+
+       /*
+        * We reach here from i915_driver_early_probe for the primary GT before
+        * its engine mask is set, so we use the device info engine mask for it.
+        * For other GTs we expect the GT-specific mask to be set before we
+        * call this function.
+        */
+       GEM_BUG_ON(!gt_is_root(gt) && !gt->info.engine_mask);
+
+       if (gt_is_root(gt))
+               mask = RUNTIME_INFO(gt->i915)->platform_engine_mask;
+       else
+               mask = gt->info.engine_mask;
+
+       return __HAS_ENGINE(mask, GSC0);
+}
+
+void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc)
+{
+       intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC);
+
+       /* we can arrive here from i915_driver_early_probe for primary
+        * GT with it being not fully setup hence check device info's
+        * engine mask
+        */
+       if (!gsc_engine_supported(gsc_uc_to_gt(gsc))) {
+               intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED);
+               return;
+       }
+}
+
+int intel_gsc_uc_init(struct intel_gsc_uc *gsc)
+{
+       struct drm_i915_private *i915 = gsc_uc_to_gt(gsc)->i915;
+       int err;
+
+       err = intel_uc_fw_init(&gsc->fw);
+       if (err)
+               goto out;
+
+       intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOADABLE);
+
+       return 0;
+
+out:
+       i915_probe_error(i915, "failed with %d\n", err);
+       return err;
+}
+
+void intel_gsc_uc_fini(struct intel_gsc_uc *gsc)
+{
+       if (!intel_uc_fw_is_loadable(&gsc->fw))
+               return;
+
+       intel_uc_fw_fini(&gsc->fw);
+}
 
--- /dev/null
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef _INTEL_GSC_UC_H_
+#define _INTEL_GSC_UC_H_
+
+#include "intel_uc_fw.h"
+
+struct intel_gsc_uc {
+       /* Generic uC firmware management */
+       struct intel_uc_fw fw;
+};
+
+void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc);
+int intel_gsc_uc_init(struct intel_gsc_uc *gsc);
+void intel_gsc_uc_fini(struct intel_gsc_uc *gsc);
+
+static inline bool intel_gsc_uc_is_supported(struct intel_gsc_uc *gsc)
+{
+       return intel_uc_fw_is_supported(&gsc->fw);
+}
+
+static inline bool intel_gsc_uc_is_wanted(struct intel_gsc_uc *gsc)
+{
+       return intel_uc_fw_is_enabled(&gsc->fw);
+}
+
+static inline bool intel_gsc_uc_is_used(struct intel_gsc_uc *gsc)
+{
+       GEM_BUG_ON(__intel_uc_fw_status(&gsc->fw) == INTEL_UC_FIRMWARE_SELECTED);
+       return intel_uc_fw_is_available(&gsc->fw);
+}
+
+#endif
 
 
 #include "gt/intel_gt.h"
 #include "gt/intel_reset.h"
+#include "intel_gsc_uc.h"
 #include "intel_guc.h"
 #include "intel_guc_ads.h"
 #include "intel_guc_submission.h"
 
        intel_guc_init_early(&uc->guc);
        intel_huc_init_early(&uc->huc);
+       intel_gsc_uc_init_early(&uc->gsc);
 
        __confirm_options(uc);
 
                                                  INTEL_UC_FIRMWARE_ERROR);
                }
 
+               if (intel_uc_wants_gsc_uc(uc)) {
+                       drm_dbg(&uc_to_gt(uc)->i915->drm,
+                               "Failed to fetch GuC: %d disabling GSC\n", err);
+                       intel_uc_fw_change_status(&uc->gsc.fw,
+                                                 INTEL_UC_FIRMWARE_ERROR);
+               }
+
                return;
        }
 
        if (intel_uc_wants_huc(uc))
                intel_uc_fw_fetch(&uc->huc.fw);
+
+       if (intel_uc_wants_gsc_uc(uc))
+               intel_uc_fw_fetch(&uc->gsc.fw);
 }
 
 static void __uc_cleanup_firmwares(struct intel_uc *uc)
 {
+       intel_uc_fw_cleanup_fetch(&uc->gsc.fw);
        intel_uc_fw_cleanup_fetch(&uc->huc.fw);
        intel_uc_fw_cleanup_fetch(&uc->guc.fw);
 }
        if (intel_uc_uses_huc(uc))
                intel_huc_init(huc);
 
+       if (intel_uc_uses_gsc_uc(uc))
+               intel_gsc_uc_init(&uc->gsc);
+
        return 0;
 }
 
 static void __uc_fini(struct intel_uc *uc)
 {
+       intel_gsc_uc_fini(&uc->gsc);
        intel_huc_fini(&uc->huc);
        intel_guc_fini(&uc->guc);
 }
 
 #ifndef _INTEL_UC_H_
 #define _INTEL_UC_H_
 
+#include "intel_gsc_uc.h"
 #include "intel_guc.h"
 #include "intel_guc_rc.h"
 #include "intel_guc_submission.h"
 
 struct intel_uc {
        struct intel_uc_ops const *ops;
+       struct intel_gsc_uc gsc;
        struct intel_guc guc;
        struct intel_huc huc;
 
 uc_state_checkers(guc, guc_submission);
 uc_state_checkers(guc, guc_slpc);
 uc_state_checkers(guc, guc_rc);
+uc_state_checkers(gsc, gsc_uc);
 
 #undef uc_state_checkers
 #undef __uc_state_checker
 
 static inline struct intel_gt *
 ____uc_fw_to_gt(struct intel_uc_fw *uc_fw, enum intel_uc_fw_type type)
 {
-       if (type == INTEL_UC_FW_TYPE_GUC)
+       GEM_BUG_ON(type >= INTEL_UC_FW_NUM_TYPES);
+
+       switch (type) {
+       case INTEL_UC_FW_TYPE_GUC:
                return container_of(uc_fw, struct intel_gt, uc.guc.fw);
+       case INTEL_UC_FW_TYPE_HUC:
+               return container_of(uc_fw, struct intel_gt, uc.huc.fw);
+       case INTEL_UC_FW_TYPE_GSC:
+               return container_of(uc_fw, struct intel_gt, uc.gsc.fw);
+       }
 
-       GEM_BUG_ON(type != INTEL_UC_FW_TYPE_HUC);
-       return container_of(uc_fw, struct intel_gt, uc.huc.fw);
+       return NULL;
 }
 
 static inline struct intel_gt *__uc_fw_to_gt(struct intel_uc_fw *uc_fw)
        int i;
        bool found;
 
+       /*
+        * GSC FW support is still not fully in place, so we're not defining
+        * the FW blob yet because we don't want the driver to attempt to load
+        * it until we're ready for it.
+        */
+       if (uc_fw->type == INTEL_UC_FW_TYPE_GSC)
+               return;
+
        /*
         * The only difference between the ADL GuC FWs is the HWConfig support.
         * ADL-N does not support HWConfig, so we should use the same binary as
        return "";
 }
 
+static const char *__override_gsc_firmware_path(struct drm_i915_private *i915)
+{
+       return i915->params.gsc_firmware_path;
+}
+
 static void __uc_fw_user_override(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
 {
        const char *path = NULL;
        case INTEL_UC_FW_TYPE_HUC:
                path = __override_huc_firmware_path(i915);
                break;
+       case INTEL_UC_FW_TYPE_GSC:
+               path = __override_gsc_firmware_path(i915);
+               break;
        }
 
        if (unlikely(path)) {
 
 
 enum intel_uc_fw_type {
        INTEL_UC_FW_TYPE_GUC = 0,
-       INTEL_UC_FW_TYPE_HUC
+       INTEL_UC_FW_TYPE_HUC,
+       INTEL_UC_FW_TYPE_GSC,
 };
-#define INTEL_UC_FW_NUM_TYPES 2
+#define INTEL_UC_FW_NUM_TYPES 3
 
 struct intel_uc_fw_ver {
        u32 major;
                return "GuC";
        case INTEL_UC_FW_TYPE_HUC:
                return "HuC";
+       case INTEL_UC_FW_TYPE_GSC:
+               return "GSC";
        }
        return "uC";
 }
 
 i915_param_named_unsafe(dmc_firmware_path, charp, 0400,
        "DMC firmware path to use instead of the default one");
 
+i915_param_named_unsafe(gsc_firmware_path, charp, 0400,
+       "GSC firmware path to use instead of the default one");
+
 i915_param_named_unsafe(enable_dp_mst, bool, 0400,
        "Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)");
 
 
        param(char *, guc_firmware_path, NULL, 0400) \
        param(char *, huc_firmware_path, NULL, 0400) \
        param(char *, dmc_firmware_path, NULL, 0400) \
+       param(char *, gsc_firmware_path, NULL, 0400) \
        param(bool, memtest, false, 0400) \
        param(int, mmio_debug, -IS_ENABLED(CONFIG_DRM_I915_DEBUG_MMIO), 0600) \
        param(int, edp_vswing, 0, 0400) \