F:     Documentation/driver-api/mei/*
 F:     drivers/misc/mei/
 F:     drivers/watchdog/mei_wdt.c
+F:     include/linux/mei_aux.h
 F:     include/linux/mei_cl_bus.h
 F:     include/uapi/linux/mei.h
 F:     samples/mei/*
 
        select VMAP_PFN
        select DRM_TTM
        select DRM_BUDDY
+       select AUXILIARY_BUS
        help
          Choose this option if you have a system that has "Intel Graphics
          Media Accelerator" or "HD Graphics" integrated graphics,
 
          gt/uc/intel_huc_debugfs.o \
          gt/uc/intel_huc_fw.o
 
+# graphics system controller (GSC) support
+i915-y += gt/intel_gsc.o
+
 # modesetting core code
 i915-y += \
        display/hsw_ips.o \
 
--- /dev/null
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2019-2022, Intel Corporation. All rights reserved.
+ */
+
+#include <linux/irq.h>
+#include <linux/mei_aux.h>
+#include "i915_drv.h"
+#include "i915_reg.h"
+#include "gt/intel_gsc.h"
+#include "gt/intel_gt.h"
+
+#define GSC_BAR_LENGTH  0x00000FFC
+
+static void gsc_irq_mask(struct irq_data *d)
+{
+       /* generic irq handling */
+}
+
+static void gsc_irq_unmask(struct irq_data *d)
+{
+       /* generic irq handling */
+}
+
+static struct irq_chip gsc_irq_chip = {
+       .name = "gsc_irq_chip",
+       .irq_mask = gsc_irq_mask,
+       .irq_unmask = gsc_irq_unmask,
+};
+
+static int gsc_irq_init(int irq)
+{
+       irq_set_chip_and_handler_name(irq, &gsc_irq_chip,
+                                     handle_simple_irq, "gsc_irq_handler");
+
+       return irq_set_chip_data(irq, NULL);
+}
+
+struct gsc_def {
+       const char *name;
+       unsigned long bar;
+       size_t bar_size;
+};
+
+/* gsc resources and definitions (HECI1 and HECI2) */
+static const struct gsc_def gsc_def_dg1[] = {
+       {
+               /* HECI1 not yet implemented. */
+       },
+       {
+               .name = "mei-gscfi",
+               .bar = DG1_GSC_HECI2_BASE,
+               .bar_size = GSC_BAR_LENGTH,
+       }
+};
+
+static void gsc_release_dev(struct device *dev)
+{
+       struct auxiliary_device *aux_dev = to_auxiliary_dev(dev);
+       struct mei_aux_device *adev = auxiliary_dev_to_mei_aux_dev(aux_dev);
+
+       kfree(adev);
+}
+
+static void gsc_destroy_one(struct intel_gsc_intf *intf)
+{
+       if (intf->adev) {
+               auxiliary_device_delete(&intf->adev->aux_dev);
+               auxiliary_device_uninit(&intf->adev->aux_dev);
+               intf->adev = NULL;
+       }
+       if (intf->irq >= 0)
+               irq_free_desc(intf->irq);
+       intf->irq = -1;
+}
+
+static void gsc_init_one(struct drm_i915_private *i915,
+                        struct intel_gsc_intf *intf,
+                        unsigned int intf_id)
+{
+       struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
+       struct mei_aux_device *adev;
+       struct auxiliary_device *aux_dev;
+       const struct gsc_def *def;
+       int ret;
+
+       intf->irq = -1;
+       intf->id = intf_id;
+
+       if (intf_id == 0 && !HAS_HECI_PXP(i915))
+               return;
+
+       def = &gsc_def_dg1[intf_id];
+
+       if (!def->name) {
+               drm_warn_once(&i915->drm, "HECI%d is not implemented!\n", intf_id + 1);
+               return;
+       }
+
+       intf->irq = irq_alloc_desc(0);
+       if (intf->irq < 0) {
+               drm_err(&i915->drm, "gsc irq error %d\n", intf->irq);
+               return;
+       }
+
+       ret = gsc_irq_init(intf->irq);
+       if (ret < 0) {
+               drm_err(&i915->drm, "gsc irq init failed %d\n", ret);
+               goto fail;
+       }
+
+       adev = kzalloc(sizeof(*adev), GFP_KERNEL);
+       if (!adev)
+               goto fail;
+
+       adev->irq = intf->irq;
+       adev->bar.parent = &pdev->resource[0];
+       adev->bar.start = def->bar + pdev->resource[0].start;
+       adev->bar.end = adev->bar.start + def->bar_size - 1;
+       adev->bar.flags = IORESOURCE_MEM;
+       adev->bar.desc = IORES_DESC_NONE;
+
+       aux_dev = &adev->aux_dev;
+       aux_dev->name = def->name;
+       aux_dev->id = (pci_domain_nr(pdev->bus) << 16) |
+                     PCI_DEVID(pdev->bus->number, pdev->devfn);
+       aux_dev->dev.parent = &pdev->dev;
+       aux_dev->dev.release = gsc_release_dev;
+
+       ret = auxiliary_device_init(aux_dev);
+       if (ret < 0) {
+               drm_err(&i915->drm, "gsc aux init failed %d\n", ret);
+               kfree(adev);
+               goto fail;
+       }
+
+       ret = auxiliary_device_add(aux_dev);
+       if (ret < 0) {
+               drm_err(&i915->drm, "gsc aux add failed %d\n", ret);
+               /* adev will be freed with the put_device() and .release sequence */
+               auxiliary_device_uninit(aux_dev);
+               goto fail;
+       }
+       intf->adev = adev;
+
+       return;
+fail:
+       gsc_destroy_one(intf);
+}
+
+static void gsc_irq_handler(struct intel_gt *gt, unsigned int intf_id)
+{
+       int ret;
+
+       if (intf_id >= INTEL_GSC_NUM_INTERFACES) {
+               drm_warn_once(>->i915->drm, "GSC irq: intf_id %d is out of range", intf_id);
+               return;
+       }
+
+       if (!HAS_HECI_GSC(gt->i915)) {
+               drm_warn_once(>->i915->drm, "GSC irq: not supported");
+               return;
+       }
+
+       if (gt->gsc.intf[intf_id].irq < 0) {
+               drm_err_ratelimited(>->i915->drm, "GSC irq: irq not set");
+               return;
+       }
+
+       ret = generic_handle_irq(gt->gsc.intf[intf_id].irq);
+       if (ret)
+               drm_err_ratelimited(>->i915->drm, "error handling GSC irq: %d\n", ret);
+}
+
+void intel_gsc_irq_handler(struct intel_gt *gt, u32 iir)
+{
+       if (iir & GSC_IRQ_INTF(0))
+               gsc_irq_handler(gt, 0);
+       if (iir & GSC_IRQ_INTF(1))
+               gsc_irq_handler(gt, 1);
+}
+
+void intel_gsc_init(struct intel_gsc *gsc, struct drm_i915_private *i915)
+{
+       unsigned int i;
+
+       if (!HAS_HECI_GSC(i915))
+               return;
+
+       for (i = 0; i < INTEL_GSC_NUM_INTERFACES; i++)
+               gsc_init_one(i915, &gsc->intf[i], i);
+}
+
+void intel_gsc_fini(struct intel_gsc *gsc)
+{
+       struct intel_gt *gt = gsc_to_gt(gsc);
+       unsigned int i;
+
+       if (!HAS_HECI_GSC(gt->i915))
+               return;
+
+       for (i = 0; i < INTEL_GSC_NUM_INTERFACES; i++)
+               gsc_destroy_one(&gsc->intf[i]);
+}
 
--- /dev/null
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2019-2022, Intel Corporation. All rights reserved.
+ */
+#ifndef __INTEL_GSC_DEV_H__
+#define __INTEL_GSC_DEV_H__
+
+#include <linux/types.h>
+
+struct drm_i915_private;
+struct intel_gt;
+struct mei_aux_device;
+
+#define INTEL_GSC_NUM_INTERFACES 2
+/*
+ * The HECI1 bit corresponds to bit15 and HECI2 to bit14.
+ * The reason for this is to allow growth for more interfaces in the future.
+ */
+#define GSC_IRQ_INTF(_x)  BIT(15 - (_x))
+
+/**
+ * struct intel_gsc - graphics security controller
+ * @intf : gsc interface
+ */
+struct intel_gsc {
+       struct intel_gsc_intf {
+               struct mei_aux_device *adev;
+               int irq;
+               unsigned int id;
+       } intf[INTEL_GSC_NUM_INTERFACES];
+};
+
+void intel_gsc_init(struct intel_gsc *gsc, struct drm_i915_private *dev_priv);
+void intel_gsc_fini(struct intel_gsc *gsc);
+void intel_gsc_irq_handler(struct intel_gt *gt, u32 iir);
+
+#endif /* __INTEL_GSC_DEV_H__ */
 
 
 void intel_gt_driver_register(struct intel_gt *gt)
 {
+       intel_gsc_init(>->gsc, gt->i915);
+
        intel_rps_driver_register(>->rps);
 
        intel_gt_debugfs_register(gt);
        intel_wakeref_t wakeref;
 
        intel_rps_driver_unregister(>->rps);
+       intel_gsc_fini(>->gsc);
 
        intel_pxp_fini(>->pxp);
 
 
        return container_of(huc, struct intel_gt, uc.huc);
 }
 
+static inline struct intel_gt *gsc_to_gt(struct intel_gsc *gsc)
+{
+       return container_of(gsc, struct intel_gt, gsc);
+}
+
 void intel_root_gt_init_early(struct drm_i915_private *i915);
 int intel_gt_assign_ggtt(struct intel_gt *gt);
 int intel_gt_init_mmio(struct intel_gt *gt);
 
        if (instance == OTHER_KCR_INSTANCE)
                return intel_pxp_irq_handler(>->pxp, iir);
 
+       if (instance == OTHER_GSC_INSTANCE)
+               return intel_gsc_irq_handler(gt, iir);
+
        WARN_ONCE(1, "unhandled other interrupt instance=0x%x, iir=0x%x\n",
                  instance, iir);
 }
        intel_uncore_write(uncore, GEN11_VCS_VECS_INTR_ENABLE,    0);
        if (CCS_MASK(gt))
                intel_uncore_write(uncore, GEN12_CCS_RSVD_INTR_ENABLE, 0);
+       if (HAS_HECI_GSC(gt->i915))
+               intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_ENABLE, 0);
 
        /* Restore masks irqs on RCS, BCS, VCS and VECS engines. */
        intel_uncore_write(uncore, GEN11_RCS0_RSVD_INTR_MASK,   ~0);
                intel_uncore_write(uncore, GEN12_CCS0_CCS1_INTR_MASK, ~0);
        if (HAS_ENGINE(gt, CCS2) || HAS_ENGINE(gt, CCS3))
                intel_uncore_write(uncore, GEN12_CCS2_CCS3_INTR_MASK, ~0);
+       if (HAS_HECI_GSC(gt->i915))
+               intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_MASK, ~0);
 
        intel_uncore_write(uncore, GEN11_GPM_WGBOXPERF_INTR_ENABLE, 0);
        intel_uncore_write(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK,  ~0);
 {
        struct intel_uncore *uncore = gt->uncore;
        u32 irqs = GT_RENDER_USER_INTERRUPT;
+       const u32 gsc_mask = GSC_IRQ_INTF(0) | GSC_IRQ_INTF(1);
        u32 dmask;
        u32 smask;
 
        intel_uncore_write(uncore, GEN11_VCS_VECS_INTR_ENABLE, dmask);
        if (CCS_MASK(gt))
                intel_uncore_write(uncore, GEN12_CCS_RSVD_INTR_ENABLE, smask);
+       if (HAS_HECI_GSC(gt->i915))
+               intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_ENABLE,
+                                  gsc_mask);
 
        /* Unmask irqs on RCS, BCS, VCS and VECS engines. */
        intel_uncore_write(uncore, GEN11_RCS0_RSVD_INTR_MASK, ~smask);
                intel_uncore_write(uncore, GEN12_CCS0_CCS1_INTR_MASK, ~dmask);
        if (HAS_ENGINE(gt, CCS2) || HAS_ENGINE(gt, CCS3))
                intel_uncore_write(uncore, GEN12_CCS2_CCS3_INTR_MASK, ~dmask);
+       if (HAS_HECI_GSC(gt->i915))
+               intel_uncore_write(uncore, GEN11_GUNIT_CSME_INTR_MASK, ~gsc_mask);
 
        /*
         * RPS interrupts will get enabled/disabled on demand when RPS itself
 
 #define   OTHER_GUC_INSTANCE                   0
 #define   OTHER_GTPM_INSTANCE                  1
 #define   OTHER_KCR_INSTANCE                   4
+#define   OTHER_GSC_INSTANCE                   6
 
 #define GEN11_IIR_REG_SELECTOR(x)              _MMIO(0x190070 + ((x) * 4))
 
 
 #include <linux/workqueue.h>
 
 #include "uc/intel_uc.h"
+#include "intel_gsc.h"
 
 #include "i915_vma.h"
 #include "intel_engine_types.h"
        struct i915_ggtt *ggtt;
 
        struct intel_uc uc;
+       struct intel_gsc gsc;
 
        struct mutex tlb_invalidate_lock;
 
 
 
 #define HAS_DMC(dev_priv)      (INTEL_INFO(dev_priv)->display.has_dmc)
 
+#define HAS_HECI_PXP(dev_priv) \
+       (INTEL_INFO(dev_priv)->has_heci_pxp)
+
+#define HAS_HECI_GSCFI(dev_priv) \
+       (INTEL_INFO(dev_priv)->has_heci_gscfi)
+
+#define HAS_HECI_GSC(dev_priv) (HAS_HECI_PXP(dev_priv) || HAS_HECI_GSCFI(dev_priv))
+
 #define HAS_MSO(i915)          (DISPLAY_VER(i915) >= 12)
 
 #define HAS_RUNTIME_PM(dev_priv) (INTEL_INFO(dev_priv)->has_runtime_pm)
 
        .has_llc = 0, \
        .has_pxp = 0, \
        .has_snoop = 1, \
-       .is_dgfx = 1
+       .is_dgfx = 1, \
+       .has_heci_gscfi = 1
 
 static const struct intel_device_info dg1_info = {
        GEN12_FEATURES,
 
 #define GEN12_COMPUTE2_RING_BASE       0x1e000
 #define GEN12_COMPUTE3_RING_BASE       0x26000
 #define BLT_RING_BASE          0x22000
+#define DG1_GSC_HECI1_BASE     0x00258000
+#define DG1_GSC_HECI2_BASE     0x00259000
 
 
 
 
        func(has_flat_ccs); \
        func(has_global_mocs); \
        func(has_gt_uc); \
+       func(has_heci_pxp); \
+       func(has_heci_gscfi); \
        func(has_guc_deprivilege); \
        func(has_l3_dpf); \
        func(has_llc); \
 
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022, Intel Corporation. All rights reserved.
+ */
+#ifndef _LINUX_MEI_AUX_H
+#define _LINUX_MEI_AUX_H
+
+#include <linux/auxiliary_bus.h>
+
+struct mei_aux_device {
+       struct auxiliary_device aux_dev;
+       int irq;
+       struct resource bar;
+};
+
+#define auxiliary_dev_to_mei_aux_dev(auxiliary_dev) \
+       container_of(auxiliary_dev, struct mei_aux_device, aux_dev)
+
+#endif /* _LINUX_MEI_AUX_H */