static u32
 make_rpcs(struct drm_i915_private *dev_priv)
 {
+       bool subslice_pg = INTEL_INFO(dev_priv)->sseu.has_subslice_pg;
+       u8 slices = hweight8(INTEL_INFO(dev_priv)->sseu.slice_mask);
+       u8 subslices = hweight8(INTEL_INFO(dev_priv)->sseu.subslice_mask[0]);
        u32 rpcs = 0;
 
        /*
        if (INTEL_GEN(dev_priv) < 9)
                return 0;
 
+       /*
+        * Since the SScount bitfield in GEN8_R_PWR_CLK_STATE is only three bits
+        * wide and Icelake has up to eight subslices, specfial programming is
+        * needed in order to correctly enable all subslices.
+        *
+        * According to documentation software must consider the configuration
+        * as 2x4x8 and hardware will translate this to 1x8x8.
+        *
+        * Furthemore, even though SScount is three bits, maximum documented
+        * value for it is four. From this some rules/restrictions follow:
+        *
+        * 1.
+        * If enabled subslice count is greater than four, two whole slices must
+        * be enabled instead.
+        *
+        * 2.
+        * When more than one slice is enabled, hardware ignores the subslice
+        * count altogether.
+        *
+        * From these restrictions it follows that it is not possible to enable
+        * a count of subslices between the SScount maximum of four restriction,
+        * and the maximum available number on a particular SKU. Either all
+        * subslices are enabled, or a count between one and four on the first
+        * slice.
+        */
+       if (IS_GEN11(dev_priv) && slices == 1 && subslices >= 4) {
+               GEM_BUG_ON(subslices & 1);
+
+               subslice_pg = false;
+               slices *= 2;
+       }
+
        /*
         * Starting in Gen9, render power gating can leave
         * slice/subslice/EU in a partially enabled state. We
         * enablement.
        */
        if (INTEL_INFO(dev_priv)->sseu.has_slice_pg) {
-               rpcs |= GEN8_RPCS_S_CNT_ENABLE;
-               rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.slice_mask) <<
-                       GEN8_RPCS_S_CNT_SHIFT;
-               rpcs |= GEN8_RPCS_ENABLE;
+               u32 mask, val = slices;
+
+               if (INTEL_GEN(dev_priv) >= 11) {
+                       mask = GEN11_RPCS_S_CNT_MASK;
+                       val <<= GEN11_RPCS_S_CNT_SHIFT;
+               } else {
+                       mask = GEN8_RPCS_S_CNT_MASK;
+                       val <<= GEN8_RPCS_S_CNT_SHIFT;
+               }
+
+               GEM_BUG_ON(val & ~mask);
+               val &= mask;
+
+               rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_S_CNT_ENABLE | val;
        }
 
-       if (INTEL_INFO(dev_priv)->sseu.has_subslice_pg) {
-               rpcs |= GEN8_RPCS_SS_CNT_ENABLE;
-               rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.subslice_mask[0]) <<
-                       GEN8_RPCS_SS_CNT_SHIFT;
-               rpcs |= GEN8_RPCS_ENABLE;
+       if (subslice_pg) {
+               u32 val = subslices;
+
+               val <<= GEN8_RPCS_SS_CNT_SHIFT;
+
+               GEM_BUG_ON(val & ~GEN8_RPCS_SS_CNT_MASK);
+               val &= GEN8_RPCS_SS_CNT_MASK;
+
+               rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_SS_CNT_ENABLE | val;
        }
 
        if (INTEL_INFO(dev_priv)->sseu.has_eu_pg) {
-               rpcs |= INTEL_INFO(dev_priv)->sseu.eu_per_subslice <<
-                       GEN8_RPCS_EU_MIN_SHIFT;
-               rpcs |= INTEL_INFO(dev_priv)->sseu.eu_per_subslice <<
-                       GEN8_RPCS_EU_MAX_SHIFT;
+               u32 val;
+
+               val = INTEL_INFO(dev_priv)->sseu.eu_per_subslice <<
+                     GEN8_RPCS_EU_MIN_SHIFT;
+               GEM_BUG_ON(val & ~GEN8_RPCS_EU_MIN_MASK);
+               val &= GEN8_RPCS_EU_MIN_MASK;
+
+               rpcs |= val;
+
+               val = INTEL_INFO(dev_priv)->sseu.eu_per_subslice <<
+                     GEN8_RPCS_EU_MAX_SHIFT;
+               GEM_BUG_ON(val & ~GEN8_RPCS_EU_MAX_MASK);
+               val &= GEN8_RPCS_EU_MAX_MASK;
+
+               rpcs |= val;
+
                rpcs |= GEN8_RPCS_ENABLE;
        }