return ret;
 }
 
+static int mei_gfx_memory_ready(struct mei_cl_device *cldev)
+{
+       struct mkhi_gfx_mem_ready req = {0};
+       unsigned int mode = MEI_CL_IO_TX_INTERNAL;
+
+       req.hdr.group_id = MKHI_GROUP_ID_GFX;
+       req.hdr.command = MKHI_GFX_MEMORY_READY_CMD_REQ;
+       req.flags = MKHI_GFX_MEM_READY_PXP_ALLOWED;
+
+       dev_dbg(&cldev->dev, "Sending memory ready command\n");
+       return __mei_cl_send(cldev->cl, (u8 *)&req, sizeof(req), 0, mode);
+}
+
 static void mei_mkhi_fix(struct mei_cl_device *cldev)
 {
        int ret;
                dev_err(&cldev->dev, "FW version command failed %d\n", ret);
        mei_cldev_disable(cldev);
 }
+
+static void mei_gsc_mkhi_fix_ver(struct mei_cl_device *cldev)
+{
+       int ret;
+
+       /* No need to enable the client if nothing is needed from it */
+       if (!cldev->bus->fw_f_fw_ver_supported &&
+           cldev->bus->pxp_mode != MEI_DEV_PXP_INIT)
+               return;
+
+       ret = mei_cldev_enable(cldev);
+       if (ret)
+               return;
+
+       if (cldev->bus->pxp_mode == MEI_DEV_PXP_INIT) {
+               ret = mei_gfx_memory_ready(cldev);
+               if (ret < 0)
+                       dev_err(&cldev->dev, "memory ready command failed %d\n", ret);
+               else
+                       dev_dbg(&cldev->dev, "memory ready command sent\n");
+               /* we go to reset after that */
+               cldev->bus->pxp_mode = MEI_DEV_PXP_SETUP;
+               goto out;
+       }
+
+       ret = mei_fwver(cldev);
+       if (ret < 0)
+               dev_err(&cldev->dev, "FW version command failed %d\n",
+                       ret);
+out:
+       mei_cldev_disable(cldev);
+}
+
 /**
  * mei_wd - wd client on the bus, change protocol version
  *   as the API has changed.
                cldev->do_match = 1;
 }
 
+/**
+ * pxp_is_ready - enable bus client if pxp is ready
+ *
+ * @cldev: me clients device
+ */
+static void pxp_is_ready(struct mei_cl_device *cldev)
+{
+       struct mei_device *bus = cldev->bus;
+
+       switch (bus->pxp_mode) {
+       case MEI_DEV_PXP_READY:
+       case MEI_DEV_PXP_DEFAULT:
+               cldev->do_match = 1;
+       break;
+       default:
+               cldev->do_match = 0;
+       break;
+       }
+}
+
 #define MEI_FIXUP(_uuid, _hook) { _uuid, _hook }
 
 static struct mei_fixup {
        MEI_FIXUP(MEI_UUID_WD, mei_wd),
        MEI_FIXUP(MEI_UUID_MKHIF_FIX, mei_mkhi_fix),
        MEI_FIXUP(MEI_UUID_IGSC_MKHI, mei_gsc_mkhi_ver),
-       MEI_FIXUP(MEI_UUID_IGSC_MKHI_FIX, mei_gsc_mkhi_ver),
+       MEI_FIXUP(MEI_UUID_IGSC_MKHI_FIX, mei_gsc_mkhi_fix_ver),
        MEI_FIXUP(MEI_UUID_HDCP, whitelist),
        MEI_FIXUP(MEI_UUID_ANY, vt_support),
-       MEI_FIXUP(MEI_UUID_PAVP, whitelist),
+       MEI_FIXUP(MEI_UUID_PAVP, pxp_is_ready),
 };
 
 /**
 
        return 0;
 }
 
+static void mei_gsc_set_ext_op_mem(const struct mei_me_hw *hw, struct resource *mem)
+{
+       u32 low = lower_32_bits(mem->start);
+       u32 hi  = upper_32_bits(mem->start);
+       u32 limit = (resource_size(mem) / SZ_4K) | GSC_EXT_OP_MEM_VALID;
+
+       iowrite32(low, hw->mem_addr + H_GSC_EXT_OP_MEM_BASE_ADDR_LO_REG);
+       iowrite32(hi, hw->mem_addr + H_GSC_EXT_OP_MEM_BASE_ADDR_HI_REG);
+       iowrite32(limit, hw->mem_addr + H_GSC_EXT_OP_MEM_LIMIT_REG);
+}
+
 static int mei_gsc_probe(struct auxiliary_device *aux_dev,
                         const struct auxiliary_device_id *aux_dev_id)
 {
 
        dev_set_drvdata(device, dev);
 
+       if (adev->ext_op_mem.start) {
+               mei_gsc_set_ext_op_mem(hw, &adev->ext_op_mem);
+               dev->pxp_mode = MEI_DEV_PXP_INIT;
+       }
+
        /* use polling */
        if (mei_me_hw_use_polling(hw)) {
                mei_disable_interrupts(dev);
 
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (c) 2003-2019, Intel Corporation. All rights reserved.
+ * Copyright (c) 2003-2022, Intel Corporation. All rights reserved.
  * Intel Management Engine Interface (Intel MEI) Linux driver
  */
 #ifndef _MEI_HW_MEI_REGS_H_
 #  define PCI_CFG_HFS_3_FW_SKU_SPS   0x00000060
 #define PCI_CFG_HFS_4         0x64
 #define PCI_CFG_HFS_5         0x68
+#  define GSC_CFG_HFS_5_BOOT_TYPE_MSK      0x00000003
+#  define GSC_CFG_HFS_5_BOOT_TYPE_PXP               3
 #define PCI_CFG_HFS_6         0x6C
 
 /* MEI registers */
 /* H_D0I3C - D0I3 Control  */
 #define H_D0I3C    0x800
 
+#define H_GSC_EXT_OP_MEM_BASE_ADDR_LO_REG 0x100
+#define H_GSC_EXT_OP_MEM_BASE_ADDR_HI_REG 0x104
+#define H_GSC_EXT_OP_MEM_LIMIT_REG        0x108
+#define GSC_EXT_OP_MEM_VALID              BIT(31)
+
 /* register bits of H_CSR (Host Control Status register) */
 /* Host Circular Buffer Depth - maximum number of 32-bit entries in CB */
 #define H_CBD             0xFF000000
 
        return (mecsr & ME_RST_HRA) == ME_RST_HRA;
 }
 
+/**
+ * mei_gsc_pxp_check - check for gsc firmware entering pxp mode
+ *
+ * @dev: the device structure
+ */
+static void mei_gsc_pxp_check(struct mei_device *dev)
+{
+       struct mei_me_hw *hw = to_me_hw(dev);
+       u32 fwsts5 = 0;
+
+       if (dev->pxp_mode == MEI_DEV_PXP_DEFAULT)
+               return;
+
+       hw->read_fws(dev, PCI_CFG_HFS_5, &fwsts5);
+       trace_mei_pci_cfg_read(dev->dev, "PCI_CFG_HFS_5", PCI_CFG_HFS_5, fwsts5);
+       if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) {
+               dev_dbg(dev->dev, "pxp mode is ready 0x%08x\n", fwsts5);
+               dev->pxp_mode = MEI_DEV_PXP_READY;
+       } else {
+               dev_dbg(dev->dev, "pxp mode is not ready 0x%08x\n", fwsts5);
+       }
+}
+
 /**
  * mei_me_hw_ready_wait - wait until the me(hw) has turned ready
  *  or timeout is reached
                return -ETIME;
        }
 
+       mei_gsc_pxp_check(dev);
+
        mei_me_hw_reset_release(dev);
        dev->recvd_hw_ready = false;
        return 0;
 
        /* check if ME wants a reset */
        if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) {
-               dev_warn(dev->dev, "FW not ready: resetting.\n");
+               dev_warn(dev->dev, "FW not ready: resetting: dev_state = %d pxp = %d\n",
+                        dev->dev_state, dev->pxp_mode);
                if (dev->dev_state == MEI_DEV_POWERING_DOWN ||
                    dev->dev_state == MEI_DEV_POWER_DOWN)
                        mei_cl_all_disconnect(dev);
 
        bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
        dev->open_handle_count = 0;
 
+       dev->pxp_mode = MEI_DEV_PXP_DEFAULT;
+
        /*
         * Reserving the first client ID
         * 0: Reserved for MEI Bus Message communications
 
        MEI_DEV_POWER_UP
 };
 
+/**
+ * enum mei_dev_pxp_mode - MEI PXP mode state
+ *
+ * @MEI_DEV_PXP_DEFAULT: PCH based device, no initailization required
+ * @MEI_DEV_PXP_INIT:    device requires initialization, send setup message to firmware
+ * @MEI_DEV_PXP_SETUP:   device is in setup stage, waiting for firmware repsonse
+ * @MEI_DEV_PXP_READY:   device initialized
+ */
+enum mei_dev_pxp_mode {
+       MEI_DEV_PXP_DEFAULT = 0,
+       MEI_DEV_PXP_INIT    = 1,
+       MEI_DEV_PXP_SETUP   = 2,
+       MEI_DEV_PXP_READY   = 3,
+};
+
 const char *mei_dev_state_str(int state);
 
 enum mei_file_transaction_states {
  * @reset_count : number of consecutive resets
  * @dev_state   : device state
  * @hbm_state   : state of host bus message protocol
+ * @pxp_mode    : PXP device mode
  * @init_clients_timer : HBM init handshake timeout
  *
  * @pg_event    : power gating event
        unsigned long reset_count;
        enum mei_dev_state dev_state;
        enum mei_hbm_state hbm_state;
+       enum mei_dev_pxp_mode pxp_mode;
        u16 init_clients_timer;
 
        /*
 
  * @aux_dev: - auxiliary device object
  * @irq: interrupt driving the mei auxiliary device
  * @bar: mmio resource bar reserved to mei auxiliary device
+ * @ext_op_mem: resource for extend operational memory
+ *              used in graphics PXP mode.
  * @slow_firmware: The device has slow underlying firmware.
  *                 Such firmware will require to use larger operation timeouts.
  */
        struct auxiliary_device aux_dev;
        int irq;
        struct resource bar;
+       struct resource ext_op_mem;
        bool slow_firmware;
 };