static void handle_gmdid(struct xe_device *xe,
                         const struct xe_device_desc *desc,
                         const struct xe_graphics_desc **graphics,
-                        const struct xe_media_desc **media)
+                        const struct xe_media_desc **media,
+                        u32 *graphics_revid,
+                        u32 *media_revid)
 {
        u32 ver;
 
        ver = peek_gmdid(xe, GMD_ID.addr);
+       *graphics_revid = REG_FIELD_GET(GMD_ID_REVID, ver);
        for (int i = 0; i < ARRAY_SIZE(graphics_ip_map); i++) {
                if (ver == graphics_ip_map[i].ver) {
                        xe->info.graphics_verx100 = ver;
        }
 
        ver = peek_gmdid(xe, GMD_ID.addr + 0x380000);
+       *media_revid = REG_FIELD_GET(GMD_ID_REVID, ver);
        for (int i = 0; i < ARRAY_SIZE(media_ip_map); i++) {
                if (ver == media_ip_map[i].ver) {
                        xe->info.media_verx100 = ver;
 {
        const struct xe_graphics_desc *graphics_desc = NULL;
        const struct xe_media_desc *media_desc = NULL;
+       u32 graphics_gmdid_revid = 0, media_gmdid_revid = 0;
        struct xe_gt *gt;
        u8 id;
 
+       xe->info.platform = desc->platform;
+       xe->info.subplatform = subplatform_desc ?
+               subplatform_desc->subplatform : XE_SUBPLATFORM_NONE;
+
        /*
         * If this platform supports GMD_ID, we'll detect the proper IP
         * descriptor to use from hardware registers. desc->graphics will only
         * ever be set at this point for platforms before GMD_ID. In that case
         * the IP descriptions and versions are simply derived from that.
         */
-       if (desc->graphics)
+       if (desc->graphics) {
                handle_pre_gmdid(xe, desc, &graphics_desc, &media_desc);
-       else
-               handle_gmdid(xe, desc, &graphics_desc, &media_desc);
+               xe->info.step = xe_step_pre_gmdid_get(xe);
+       } else {
+               handle_gmdid(xe, desc, &graphics_desc, &media_desc,
+                            &graphics_gmdid_revid, &media_gmdid_revid);
+               xe->info.step = xe_step_gmdid_get(xe,
+                                                 graphics_gmdid_revid,
+                                                 media_gmdid_revid);
+       }
 
        /*
         * If we couldn't detect the graphics IP, that's considered a fatal
                return -ENODEV;
 
        xe->info.is_dgfx = desc->is_dgfx;
-       xe->info.platform = desc->platform;
        xe->info.graphics_name = graphics_desc->name;
        xe->info.media_name = media_desc ? media_desc->name : "none";
        xe->info.has_4tile = desc->has_4tile;
        if (MEDIA_VER(xe) >= 13)
                xe->info.tile_count++;
 
-       xe->info.subplatform = subplatform_desc ?
-               subplatform_desc->subplatform : XE_SUBPLATFORM_NONE;
-       xe->info.step = xe_step_get(xe);
-
        for (id = 0; id < xe->info.tile_count; ++id) {
                gt = xe->gt + id;
                gt->info.id = id;
 
 
 __diag_pop();
 
-struct xe_step_info xe_step_get(struct xe_device *xe)
+/**
+ * xe_step_pre_gmdid_get - Determine IP steppings from PCI revid
+ * @xe: Xe device
+ *
+ * Convert the PCI revid into proper IP steppings.  This should only be
+ * used on platforms that do not have GMD_ID support.
+ */
+struct xe_step_info xe_step_pre_gmdid_get(struct xe_device *xe)
 {
        const struct xe_step_info *revids = NULL;
        struct xe_step_info step = {};
        return step;
 }
 
+/**
+ * xe_step_gmdid_get - Determine IP steppings from GMD_ID revid fields
+ * @xe: Xe device
+ * @graphics_gmdid_revid: value of graphics GMD_ID register's revid field
+ * @media_gmdid_revid: value of media GMD_ID register's revid field
+ *
+ * Convert the revid fields of the GMD_ID registers into proper IP steppings.
+ *
+ * GMD_ID revid values are currently expected to have consistent meanings on
+ * all platforms:  major steppings (A0, B0, etc.) are 4 apart, with minor
+ * steppings (A1, A2, etc.) taking the values in between.
+ */
+struct xe_step_info xe_step_gmdid_get(struct xe_device *xe,
+                                     u32 graphics_gmdid_revid,
+                                     u32 media_gmdid_revid)
+{
+       struct xe_step_info step = {
+               .graphics = STEP_A0 + graphics_gmdid_revid,
+               .media = STEP_A0 + media_gmdid_revid,
+       };
+
+       if (step.graphics >= STEP_FUTURE) {
+               step.graphics = STEP_FUTURE;
+               drm_dbg(&xe->drm, "Graphics GMD_ID revid value %d treated as future stepping\n",
+                       graphics_gmdid_revid);
+       }
+
+       if (step.media >= STEP_FUTURE) {
+               step.media = STEP_FUTURE;
+               drm_dbg(&xe->drm, "Media GMD_ID revid value %d treated as future stepping\n",
+                       graphics_gmdid_revid);
+       }
+
+       return step;
+}
+
 #define STEP_NAME_CASE(name)   \
        case STEP_##name:       \
                return #name;