v.swizzle = default_vec2_swizzle;
 
                         state->reads_point_coord = true;
+                } else if (location == VARYING_SLOT_FACE) {
+                        v.index = 4;
+                        v.format = MALI_R32I;
+                        v.swizzle = default_vec1_swizzle;
+
+                        state->reads_face = true;
                 } else {
                         v.index = 0;
                 }
 
         slot->stride = slot->size = slot->shift = slot->extra_flags = 0;
 }
 
+static void
+panfrost_emit_front_face(union mali_attr *slot)
+{
+        slot->elements = MALI_VARYING_FRONT_FACING | MALI_ATTR_INTERNAL;
+}
+
 static void
 panfrost_emit_varying_descriptor(
         struct panfrost_context *ctx,
                 ctx->payload_tiler.primitive_size.pointer =
                         panfrost_emit_varyings(ctx, &varyings[idx++],
                                                2, vertex_count);
+        } else if (fs->reads_face) {
+                /* Dummy to advance index */
+                ++idx;
         }
 
         if (fs->reads_point_coord) {
                 /* Special descriptor */
                 panfrost_emit_point_coord(&varyings[idx++]);
+        } else if (fs->reads_face) {
+                ++idx;
+        }
+
+        if (fs->reads_face) {
+                panfrost_emit_front_face(&varyings[idx++]);
         }
 
         mali_ptr varyings_p = panfrost_upload_transient(ctx, &varyings, idx * sizeof(union mali_attr));
 
         case PIPE_CAP_GENERATE_MIPMAP:
                 return 1;
 
+        /* We would prefer varyings */
+        case PIPE_CAP_TGSI_FS_FACE_IS_INTEGER_SYSVAL:
+        case PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL:
+                return 0;
+
         case PIPE_CAP_SEAMLESS_CUBE_MAP:
         case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE:
                 return 1;