| .. | .. |
|---|
| 22 | 22 | * |
|---|
| 23 | 23 | */ |
|---|
| 24 | 24 | |
|---|
| 25 | +#include <asm/iosf_mbi.h> |
|---|
| 26 | + |
|---|
| 25 | 27 | #include "i915_drv.h" |
|---|
| 26 | | -#include "intel_drv.h" |
|---|
| 28 | +#include "intel_sideband.h" |
|---|
| 27 | 29 | |
|---|
| 28 | 30 | /* |
|---|
| 29 | 31 | * IOSF sideband, see VLV2_SidebandMsg_HAS.docx and |
|---|
| .. | .. |
|---|
| 39 | 41 | /* Private register write, double-word addressing, non-posted */ |
|---|
| 40 | 42 | #define SB_CRWRDA_NP 0x07 |
|---|
| 41 | 43 | |
|---|
| 42 | | -static int vlv_sideband_rw(struct drm_i915_private *dev_priv, u32 devfn, |
|---|
| 43 | | - u32 port, u32 opcode, u32 addr, u32 *val) |
|---|
| 44 | +static void ping(void *info) |
|---|
| 44 | 45 | { |
|---|
| 45 | | - u32 cmd, be = 0xf, bar = 0; |
|---|
| 46 | | - bool is_read = (opcode == SB_MRD_NP || opcode == SB_CRRDDA_NP); |
|---|
| 46 | +} |
|---|
| 47 | 47 | |
|---|
| 48 | | - cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) | |
|---|
| 49 | | - (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) | |
|---|
| 50 | | - (bar << IOSF_BAR_SHIFT); |
|---|
| 48 | +static void __vlv_punit_get(struct drm_i915_private *i915) |
|---|
| 49 | +{ |
|---|
| 50 | + iosf_mbi_punit_acquire(); |
|---|
| 51 | 51 | |
|---|
| 52 | | - WARN_ON(!mutex_is_locked(&dev_priv->sb_lock)); |
|---|
| 52 | + /* |
|---|
| 53 | + * Prevent the cpu from sleeping while we use this sideband, otherwise |
|---|
| 54 | + * the punit may cause a machine hang. The issue appears to be isolated |
|---|
| 55 | + * with changing the power state of the CPU package while changing |
|---|
| 56 | + * the power state via the punit, and we have only observed it |
|---|
| 57 | + * reliably on 4-core Baytail systems suggesting the issue is in the |
|---|
| 58 | + * power delivery mechanism and likely to be be board/function |
|---|
| 59 | + * specific. Hence we presume the workaround needs only be applied |
|---|
| 60 | + * to the Valleyview P-unit and not all sideband communications. |
|---|
| 61 | + */ |
|---|
| 62 | + if (IS_VALLEYVIEW(i915)) { |
|---|
| 63 | + cpu_latency_qos_update_request(&i915->sb_qos, 0); |
|---|
| 64 | + on_each_cpu(ping, NULL, 1); |
|---|
| 65 | + } |
|---|
| 66 | +} |
|---|
| 53 | 67 | |
|---|
| 54 | | - if (intel_wait_for_register(dev_priv, |
|---|
| 68 | +static void __vlv_punit_put(struct drm_i915_private *i915) |
|---|
| 69 | +{ |
|---|
| 70 | + if (IS_VALLEYVIEW(i915)) |
|---|
| 71 | + cpu_latency_qos_update_request(&i915->sb_qos, |
|---|
| 72 | + PM_QOS_DEFAULT_VALUE); |
|---|
| 73 | + |
|---|
| 74 | + iosf_mbi_punit_release(); |
|---|
| 75 | +} |
|---|
| 76 | + |
|---|
| 77 | +void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports) |
|---|
| 78 | +{ |
|---|
| 79 | + if (ports & BIT(VLV_IOSF_SB_PUNIT)) |
|---|
| 80 | + __vlv_punit_get(i915); |
|---|
| 81 | + |
|---|
| 82 | + mutex_lock(&i915->sb_lock); |
|---|
| 83 | +} |
|---|
| 84 | + |
|---|
| 85 | +void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports) |
|---|
| 86 | +{ |
|---|
| 87 | + mutex_unlock(&i915->sb_lock); |
|---|
| 88 | + |
|---|
| 89 | + if (ports & BIT(VLV_IOSF_SB_PUNIT)) |
|---|
| 90 | + __vlv_punit_put(i915); |
|---|
| 91 | +} |
|---|
| 92 | + |
|---|
| 93 | +static int vlv_sideband_rw(struct drm_i915_private *i915, |
|---|
| 94 | + u32 devfn, u32 port, u32 opcode, |
|---|
| 95 | + u32 addr, u32 *val) |
|---|
| 96 | +{ |
|---|
| 97 | + struct intel_uncore *uncore = &i915->uncore; |
|---|
| 98 | + const bool is_read = (opcode == SB_MRD_NP || opcode == SB_CRRDDA_NP); |
|---|
| 99 | + int err; |
|---|
| 100 | + |
|---|
| 101 | + lockdep_assert_held(&i915->sb_lock); |
|---|
| 102 | + if (port == IOSF_PORT_PUNIT) |
|---|
| 103 | + iosf_mbi_assert_punit_acquired(); |
|---|
| 104 | + |
|---|
| 105 | + /* Flush the previous comms, just in case it failed last time. */ |
|---|
| 106 | + if (intel_wait_for_register(uncore, |
|---|
| 55 | 107 | VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0, |
|---|
| 56 | 108 | 5)) { |
|---|
| 57 | | - DRM_DEBUG_DRIVER("IOSF sideband idle wait (%s) timed out\n", |
|---|
| 58 | | - is_read ? "read" : "write"); |
|---|
| 109 | + drm_dbg(&i915->drm, "IOSF sideband idle wait (%s) timed out\n", |
|---|
| 110 | + is_read ? "read" : "write"); |
|---|
| 59 | 111 | return -EAGAIN; |
|---|
| 60 | 112 | } |
|---|
| 61 | 113 | |
|---|
| 62 | | - I915_WRITE(VLV_IOSF_ADDR, addr); |
|---|
| 63 | | - I915_WRITE(VLV_IOSF_DATA, is_read ? 0 : *val); |
|---|
| 64 | | - I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd); |
|---|
| 114 | + preempt_disable(); |
|---|
| 65 | 115 | |
|---|
| 66 | | - if (intel_wait_for_register(dev_priv, |
|---|
| 67 | | - VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0, |
|---|
| 68 | | - 5)) { |
|---|
| 69 | | - DRM_DEBUG_DRIVER("IOSF sideband finish wait (%s) timed out\n", |
|---|
| 70 | | - is_read ? "read" : "write"); |
|---|
| 71 | | - return -ETIMEDOUT; |
|---|
| 116 | + intel_uncore_write_fw(uncore, VLV_IOSF_ADDR, addr); |
|---|
| 117 | + intel_uncore_write_fw(uncore, VLV_IOSF_DATA, is_read ? 0 : *val); |
|---|
| 118 | + intel_uncore_write_fw(uncore, VLV_IOSF_DOORBELL_REQ, |
|---|
| 119 | + (devfn << IOSF_DEVFN_SHIFT) | |
|---|
| 120 | + (opcode << IOSF_OPCODE_SHIFT) | |
|---|
| 121 | + (port << IOSF_PORT_SHIFT) | |
|---|
| 122 | + (0xf << IOSF_BYTE_ENABLES_SHIFT) | |
|---|
| 123 | + (0 << IOSF_BAR_SHIFT) | |
|---|
| 124 | + IOSF_SB_BUSY); |
|---|
| 125 | + |
|---|
| 126 | + if (__intel_wait_for_register_fw(uncore, |
|---|
| 127 | + VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0, |
|---|
| 128 | + 10000, 0, NULL) == 0) { |
|---|
| 129 | + if (is_read) |
|---|
| 130 | + *val = intel_uncore_read_fw(uncore, VLV_IOSF_DATA); |
|---|
| 131 | + err = 0; |
|---|
| 132 | + } else { |
|---|
| 133 | + drm_dbg(&i915->drm, "IOSF sideband finish wait (%s) timed out\n", |
|---|
| 134 | + is_read ? "read" : "write"); |
|---|
| 135 | + err = -ETIMEDOUT; |
|---|
| 72 | 136 | } |
|---|
| 73 | 137 | |
|---|
| 74 | | - if (is_read) |
|---|
| 75 | | - *val = I915_READ(VLV_IOSF_DATA); |
|---|
| 76 | | - |
|---|
| 77 | | - return 0; |
|---|
| 78 | | -} |
|---|
| 79 | | - |
|---|
| 80 | | -u32 vlv_punit_read(struct drm_i915_private *dev_priv, u32 addr) |
|---|
| 81 | | -{ |
|---|
| 82 | | - u32 val = 0; |
|---|
| 83 | | - |
|---|
| 84 | | - WARN_ON(!mutex_is_locked(&dev_priv->pcu_lock)); |
|---|
| 85 | | - |
|---|
| 86 | | - mutex_lock(&dev_priv->sb_lock); |
|---|
| 87 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT, |
|---|
| 88 | | - SB_CRRDDA_NP, addr, &val); |
|---|
| 89 | | - mutex_unlock(&dev_priv->sb_lock); |
|---|
| 90 | | - |
|---|
| 91 | | - return val; |
|---|
| 92 | | -} |
|---|
| 93 | | - |
|---|
| 94 | | -int vlv_punit_write(struct drm_i915_private *dev_priv, u32 addr, u32 val) |
|---|
| 95 | | -{ |
|---|
| 96 | | - int err; |
|---|
| 97 | | - |
|---|
| 98 | | - WARN_ON(!mutex_is_locked(&dev_priv->pcu_lock)); |
|---|
| 99 | | - |
|---|
| 100 | | - mutex_lock(&dev_priv->sb_lock); |
|---|
| 101 | | - err = vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT, |
|---|
| 102 | | - SB_CRWRDA_NP, addr, &val); |
|---|
| 103 | | - mutex_unlock(&dev_priv->sb_lock); |
|---|
| 138 | + preempt_enable(); |
|---|
| 104 | 139 | |
|---|
| 105 | 140 | return err; |
|---|
| 106 | 141 | } |
|---|
| 107 | 142 | |
|---|
| 108 | | -u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg) |
|---|
| 143 | +u32 vlv_punit_read(struct drm_i915_private *i915, u32 addr) |
|---|
| 109 | 144 | { |
|---|
| 110 | 145 | u32 val = 0; |
|---|
| 111 | 146 | |
|---|
| 112 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT, |
|---|
| 147 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT, |
|---|
| 148 | + SB_CRRDDA_NP, addr, &val); |
|---|
| 149 | + |
|---|
| 150 | + return val; |
|---|
| 151 | +} |
|---|
| 152 | + |
|---|
| 153 | +int vlv_punit_write(struct drm_i915_private *i915, u32 addr, u32 val) |
|---|
| 154 | +{ |
|---|
| 155 | + return vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT, |
|---|
| 156 | + SB_CRWRDA_NP, addr, &val); |
|---|
| 157 | +} |
|---|
| 158 | + |
|---|
| 159 | +u32 vlv_bunit_read(struct drm_i915_private *i915, u32 reg) |
|---|
| 160 | +{ |
|---|
| 161 | + u32 val = 0; |
|---|
| 162 | + |
|---|
| 163 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT, |
|---|
| 113 | 164 | SB_CRRDDA_NP, reg, &val); |
|---|
| 114 | 165 | |
|---|
| 115 | 166 | return val; |
|---|
| 116 | 167 | } |
|---|
| 117 | 168 | |
|---|
| 118 | | -void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) |
|---|
| 169 | +void vlv_bunit_write(struct drm_i915_private *i915, u32 reg, u32 val) |
|---|
| 119 | 170 | { |
|---|
| 120 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT, |
|---|
| 171 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT, |
|---|
| 121 | 172 | SB_CRWRDA_NP, reg, &val); |
|---|
| 122 | 173 | } |
|---|
| 123 | 174 | |
|---|
| 124 | | -u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr) |
|---|
| 175 | +u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr) |
|---|
| 125 | 176 | { |
|---|
| 126 | 177 | u32 val = 0; |
|---|
| 127 | 178 | |
|---|
| 128 | | - WARN_ON(!mutex_is_locked(&dev_priv->pcu_lock)); |
|---|
| 129 | | - |
|---|
| 130 | | - mutex_lock(&dev_priv->sb_lock); |
|---|
| 131 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_NC, |
|---|
| 179 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_NC, |
|---|
| 132 | 180 | SB_CRRDDA_NP, addr, &val); |
|---|
| 133 | | - mutex_unlock(&dev_priv->sb_lock); |
|---|
| 134 | 181 | |
|---|
| 135 | 182 | return val; |
|---|
| 136 | 183 | } |
|---|
| 137 | 184 | |
|---|
| 138 | | -u32 vlv_iosf_sb_read(struct drm_i915_private *dev_priv, u8 port, u32 reg) |
|---|
| 185 | +u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg) |
|---|
| 139 | 186 | { |
|---|
| 140 | 187 | u32 val = 0; |
|---|
| 141 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), port, |
|---|
| 188 | + |
|---|
| 189 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, |
|---|
| 142 | 190 | SB_CRRDDA_NP, reg, &val); |
|---|
| 191 | + |
|---|
| 143 | 192 | return val; |
|---|
| 144 | 193 | } |
|---|
| 145 | 194 | |
|---|
| 146 | | -void vlv_iosf_sb_write(struct drm_i915_private *dev_priv, |
|---|
| 195 | +void vlv_iosf_sb_write(struct drm_i915_private *i915, |
|---|
| 147 | 196 | u8 port, u32 reg, u32 val) |
|---|
| 148 | 197 | { |
|---|
| 149 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), port, |
|---|
| 198 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, |
|---|
| 150 | 199 | SB_CRWRDA_NP, reg, &val); |
|---|
| 151 | 200 | } |
|---|
| 152 | 201 | |
|---|
| 153 | | -u32 vlv_cck_read(struct drm_i915_private *dev_priv, u32 reg) |
|---|
| 202 | +u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg) |
|---|
| 154 | 203 | { |
|---|
| 155 | 204 | u32 val = 0; |
|---|
| 156 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCK, |
|---|
| 205 | + |
|---|
| 206 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK, |
|---|
| 157 | 207 | SB_CRRDDA_NP, reg, &val); |
|---|
| 208 | + |
|---|
| 158 | 209 | return val; |
|---|
| 159 | 210 | } |
|---|
| 160 | 211 | |
|---|
| 161 | | -void vlv_cck_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) |
|---|
| 212 | +void vlv_cck_write(struct drm_i915_private *i915, u32 reg, u32 val) |
|---|
| 162 | 213 | { |
|---|
| 163 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCK, |
|---|
| 214 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK, |
|---|
| 164 | 215 | SB_CRWRDA_NP, reg, &val); |
|---|
| 165 | 216 | } |
|---|
| 166 | 217 | |
|---|
| 167 | | -u32 vlv_ccu_read(struct drm_i915_private *dev_priv, u32 reg) |
|---|
| 218 | +u32 vlv_ccu_read(struct drm_i915_private *i915, u32 reg) |
|---|
| 168 | 219 | { |
|---|
| 169 | 220 | u32 val = 0; |
|---|
| 170 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCU, |
|---|
| 221 | + |
|---|
| 222 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU, |
|---|
| 171 | 223 | SB_CRRDDA_NP, reg, &val); |
|---|
| 224 | + |
|---|
| 172 | 225 | return val; |
|---|
| 173 | 226 | } |
|---|
| 174 | 227 | |
|---|
| 175 | | -void vlv_ccu_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) |
|---|
| 228 | +void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val) |
|---|
| 176 | 229 | { |
|---|
| 177 | | - vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCU, |
|---|
| 230 | + vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU, |
|---|
| 178 | 231 | SB_CRWRDA_NP, reg, &val); |
|---|
| 179 | 232 | } |
|---|
| 180 | 233 | |
|---|
| 181 | | -u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) |
|---|
| 234 | +static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy phy) |
|---|
| 182 | 235 | { |
|---|
| 236 | + /* |
|---|
| 237 | + * IOSF_PORT_DPIO: VLV x2 PHY (DP/HDMI B and C), CHV x1 PHY (DP/HDMI D) |
|---|
| 238 | + * IOSF_PORT_DPIO_2: CHV x2 PHY (DP/HDMI B and C) |
|---|
| 239 | + */ |
|---|
| 240 | + if (IS_CHERRYVIEW(i915)) |
|---|
| 241 | + return phy == DPIO_PHY0 ? IOSF_PORT_DPIO_2 : IOSF_PORT_DPIO; |
|---|
| 242 | + else |
|---|
| 243 | + return IOSF_PORT_DPIO; |
|---|
| 244 | +} |
|---|
| 245 | + |
|---|
| 246 | +u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg) |
|---|
| 247 | +{ |
|---|
| 248 | + u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); |
|---|
| 183 | 249 | u32 val = 0; |
|---|
| 184 | 250 | |
|---|
| 185 | | - vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)), |
|---|
| 186 | | - SB_MRD_NP, reg, &val); |
|---|
| 251 | + vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val); |
|---|
| 187 | 252 | |
|---|
| 188 | 253 | /* |
|---|
| 189 | 254 | * FIXME: There might be some registers where all 1's is a valid value, |
|---|
| 190 | 255 | * so ideally we should check the register offset instead... |
|---|
| 191 | 256 | */ |
|---|
| 192 | | - WARN(val == 0xffffffff, "DPIO read pipe %c reg 0x%x == 0x%x\n", |
|---|
| 193 | | - pipe_name(pipe), reg, val); |
|---|
| 257 | + drm_WARN(&i915->drm, val == 0xffffffff, |
|---|
| 258 | + "DPIO read pipe %c reg 0x%x == 0x%x\n", |
|---|
| 259 | + pipe_name(pipe), reg, val); |
|---|
| 194 | 260 | |
|---|
| 195 | 261 | return val; |
|---|
| 196 | 262 | } |
|---|
| 197 | 263 | |
|---|
| 198 | | -void vlv_dpio_write(struct drm_i915_private *dev_priv, enum pipe pipe, int reg, u32 val) |
|---|
| 264 | +void vlv_dpio_write(struct drm_i915_private *i915, |
|---|
| 265 | + enum pipe pipe, int reg, u32 val) |
|---|
| 199 | 266 | { |
|---|
| 200 | | - vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)), |
|---|
| 201 | | - SB_MWR_NP, reg, &val); |
|---|
| 267 | + u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); |
|---|
| 268 | + |
|---|
| 269 | + vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val); |
|---|
| 270 | +} |
|---|
| 271 | + |
|---|
| 272 | +u32 vlv_flisdsi_read(struct drm_i915_private *i915, u32 reg) |
|---|
| 273 | +{ |
|---|
| 274 | + u32 val = 0; |
|---|
| 275 | + |
|---|
| 276 | + vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRRDDA_NP, |
|---|
| 277 | + reg, &val); |
|---|
| 278 | + return val; |
|---|
| 279 | +} |
|---|
| 280 | + |
|---|
| 281 | +void vlv_flisdsi_write(struct drm_i915_private *i915, u32 reg, u32 val) |
|---|
| 282 | +{ |
|---|
| 283 | + vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRWRDA_NP, |
|---|
| 284 | + reg, &val); |
|---|
| 202 | 285 | } |
|---|
| 203 | 286 | |
|---|
| 204 | 287 | /* SBI access */ |
|---|
| 205 | | -u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, |
|---|
| 288 | +static int intel_sbi_rw(struct drm_i915_private *i915, u16 reg, |
|---|
| 289 | + enum intel_sbi_destination destination, |
|---|
| 290 | + u32 *val, bool is_read) |
|---|
| 291 | +{ |
|---|
| 292 | + struct intel_uncore *uncore = &i915->uncore; |
|---|
| 293 | + u32 cmd; |
|---|
| 294 | + |
|---|
| 295 | + lockdep_assert_held(&i915->sb_lock); |
|---|
| 296 | + |
|---|
| 297 | + if (intel_wait_for_register_fw(uncore, |
|---|
| 298 | + SBI_CTL_STAT, SBI_BUSY, 0, |
|---|
| 299 | + 100)) { |
|---|
| 300 | + drm_err(&i915->drm, |
|---|
| 301 | + "timeout waiting for SBI to become ready\n"); |
|---|
| 302 | + return -EBUSY; |
|---|
| 303 | + } |
|---|
| 304 | + |
|---|
| 305 | + intel_uncore_write_fw(uncore, SBI_ADDR, (u32)reg << 16); |
|---|
| 306 | + intel_uncore_write_fw(uncore, SBI_DATA, is_read ? 0 : *val); |
|---|
| 307 | + |
|---|
| 308 | + if (destination == SBI_ICLK) |
|---|
| 309 | + cmd = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD; |
|---|
| 310 | + else |
|---|
| 311 | + cmd = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD; |
|---|
| 312 | + if (!is_read) |
|---|
| 313 | + cmd |= BIT(8); |
|---|
| 314 | + intel_uncore_write_fw(uncore, SBI_CTL_STAT, cmd | SBI_BUSY); |
|---|
| 315 | + |
|---|
| 316 | + if (__intel_wait_for_register_fw(uncore, |
|---|
| 317 | + SBI_CTL_STAT, SBI_BUSY, 0, |
|---|
| 318 | + 100, 100, &cmd)) { |
|---|
| 319 | + drm_err(&i915->drm, |
|---|
| 320 | + "timeout waiting for SBI to complete read\n"); |
|---|
| 321 | + return -ETIMEDOUT; |
|---|
| 322 | + } |
|---|
| 323 | + |
|---|
| 324 | + if (cmd & SBI_RESPONSE_FAIL) { |
|---|
| 325 | + drm_err(&i915->drm, "error during SBI read of reg %x\n", reg); |
|---|
| 326 | + return -ENXIO; |
|---|
| 327 | + } |
|---|
| 328 | + |
|---|
| 329 | + if (is_read) |
|---|
| 330 | + *val = intel_uncore_read_fw(uncore, SBI_DATA); |
|---|
| 331 | + |
|---|
| 332 | + return 0; |
|---|
| 333 | +} |
|---|
| 334 | + |
|---|
| 335 | +u32 intel_sbi_read(struct drm_i915_private *i915, u16 reg, |
|---|
| 206 | 336 | enum intel_sbi_destination destination) |
|---|
| 207 | 337 | { |
|---|
| 208 | | - u32 value = 0; |
|---|
| 209 | | - WARN_ON(!mutex_is_locked(&dev_priv->sb_lock)); |
|---|
| 338 | + u32 result = 0; |
|---|
| 210 | 339 | |
|---|
| 211 | | - if (intel_wait_for_register(dev_priv, |
|---|
| 212 | | - SBI_CTL_STAT, SBI_BUSY, 0, |
|---|
| 213 | | - 100)) { |
|---|
| 214 | | - DRM_ERROR("timeout waiting for SBI to become ready\n"); |
|---|
| 215 | | - return 0; |
|---|
| 216 | | - } |
|---|
| 340 | + intel_sbi_rw(i915, reg, destination, &result, true); |
|---|
| 217 | 341 | |
|---|
| 218 | | - I915_WRITE(SBI_ADDR, (reg << 16)); |
|---|
| 219 | | - I915_WRITE(SBI_DATA, 0); |
|---|
| 220 | | - |
|---|
| 221 | | - if (destination == SBI_ICLK) |
|---|
| 222 | | - value = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD; |
|---|
| 223 | | - else |
|---|
| 224 | | - value = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD; |
|---|
| 225 | | - I915_WRITE(SBI_CTL_STAT, value | SBI_BUSY); |
|---|
| 226 | | - |
|---|
| 227 | | - if (intel_wait_for_register(dev_priv, |
|---|
| 228 | | - SBI_CTL_STAT, |
|---|
| 229 | | - SBI_BUSY, |
|---|
| 230 | | - 0, |
|---|
| 231 | | - 100)) { |
|---|
| 232 | | - DRM_ERROR("timeout waiting for SBI to complete read\n"); |
|---|
| 233 | | - return 0; |
|---|
| 234 | | - } |
|---|
| 235 | | - |
|---|
| 236 | | - if (I915_READ(SBI_CTL_STAT) & SBI_RESPONSE_FAIL) { |
|---|
| 237 | | - DRM_ERROR("error during SBI read of reg %x\n", reg); |
|---|
| 238 | | - return 0; |
|---|
| 239 | | - } |
|---|
| 240 | | - |
|---|
| 241 | | - return I915_READ(SBI_DATA); |
|---|
| 342 | + return result; |
|---|
| 242 | 343 | } |
|---|
| 243 | 344 | |
|---|
| 244 | | -void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, |
|---|
| 345 | +void intel_sbi_write(struct drm_i915_private *i915, u16 reg, u32 value, |
|---|
| 245 | 346 | enum intel_sbi_destination destination) |
|---|
| 246 | 347 | { |
|---|
| 247 | | - u32 tmp; |
|---|
| 348 | + intel_sbi_rw(i915, reg, destination, &value, false); |
|---|
| 349 | +} |
|---|
| 248 | 350 | |
|---|
| 249 | | - WARN_ON(!mutex_is_locked(&dev_priv->sb_lock)); |
|---|
| 250 | | - |
|---|
| 251 | | - if (intel_wait_for_register(dev_priv, |
|---|
| 252 | | - SBI_CTL_STAT, SBI_BUSY, 0, |
|---|
| 253 | | - 100)) { |
|---|
| 254 | | - DRM_ERROR("timeout waiting for SBI to become ready\n"); |
|---|
| 255 | | - return; |
|---|
| 351 | +static int gen6_check_mailbox_status(u32 mbox) |
|---|
| 352 | +{ |
|---|
| 353 | + switch (mbox & GEN6_PCODE_ERROR_MASK) { |
|---|
| 354 | + case GEN6_PCODE_SUCCESS: |
|---|
| 355 | + return 0; |
|---|
| 356 | + case GEN6_PCODE_UNIMPLEMENTED_CMD: |
|---|
| 357 | + return -ENODEV; |
|---|
| 358 | + case GEN6_PCODE_ILLEGAL_CMD: |
|---|
| 359 | + return -ENXIO; |
|---|
| 360 | + case GEN6_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: |
|---|
| 361 | + case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: |
|---|
| 362 | + return -EOVERFLOW; |
|---|
| 363 | + case GEN6_PCODE_TIMEOUT: |
|---|
| 364 | + return -ETIMEDOUT; |
|---|
| 365 | + default: |
|---|
| 366 | + MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK); |
|---|
| 367 | + return 0; |
|---|
| 256 | 368 | } |
|---|
| 369 | +} |
|---|
| 257 | 370 | |
|---|
| 258 | | - I915_WRITE(SBI_ADDR, (reg << 16)); |
|---|
| 259 | | - I915_WRITE(SBI_DATA, value); |
|---|
| 371 | +static int gen7_check_mailbox_status(u32 mbox) |
|---|
| 372 | +{ |
|---|
| 373 | + switch (mbox & GEN6_PCODE_ERROR_MASK) { |
|---|
| 374 | + case GEN6_PCODE_SUCCESS: |
|---|
| 375 | + return 0; |
|---|
| 376 | + case GEN6_PCODE_ILLEGAL_CMD: |
|---|
| 377 | + return -ENXIO; |
|---|
| 378 | + case GEN7_PCODE_TIMEOUT: |
|---|
| 379 | + return -ETIMEDOUT; |
|---|
| 380 | + case GEN7_PCODE_ILLEGAL_DATA: |
|---|
| 381 | + return -EINVAL; |
|---|
| 382 | + case GEN11_PCODE_ILLEGAL_SUBCOMMAND: |
|---|
| 383 | + return -ENXIO; |
|---|
| 384 | + case GEN11_PCODE_LOCKED: |
|---|
| 385 | + return -EBUSY; |
|---|
| 386 | + case GEN11_PCODE_REJECTED: |
|---|
| 387 | + return -EACCES; |
|---|
| 388 | + case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: |
|---|
| 389 | + return -EOVERFLOW; |
|---|
| 390 | + default: |
|---|
| 391 | + MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK); |
|---|
| 392 | + return 0; |
|---|
| 393 | + } |
|---|
| 394 | +} |
|---|
| 260 | 395 | |
|---|
| 261 | | - if (destination == SBI_ICLK) |
|---|
| 262 | | - tmp = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRWR; |
|---|
| 396 | +static int __sandybridge_pcode_rw(struct drm_i915_private *i915, |
|---|
| 397 | + u32 mbox, u32 *val, u32 *val1, |
|---|
| 398 | + int fast_timeout_us, |
|---|
| 399 | + int slow_timeout_ms, |
|---|
| 400 | + bool is_read) |
|---|
| 401 | +{ |
|---|
| 402 | + struct intel_uncore *uncore = &i915->uncore; |
|---|
| 403 | + |
|---|
| 404 | + lockdep_assert_held(&i915->sb_lock); |
|---|
| 405 | + |
|---|
| 406 | + /* |
|---|
| 407 | + * GEN6_PCODE_* are outside of the forcewake domain, we can |
|---|
| 408 | + * use te fw I915_READ variants to reduce the amount of work |
|---|
| 409 | + * required when reading/writing. |
|---|
| 410 | + */ |
|---|
| 411 | + |
|---|
| 412 | + if (intel_uncore_read_fw(uncore, GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) |
|---|
| 413 | + return -EAGAIN; |
|---|
| 414 | + |
|---|
| 415 | + intel_uncore_write_fw(uncore, GEN6_PCODE_DATA, *val); |
|---|
| 416 | + intel_uncore_write_fw(uncore, GEN6_PCODE_DATA1, val1 ? *val1 : 0); |
|---|
| 417 | + intel_uncore_write_fw(uncore, |
|---|
| 418 | + GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox); |
|---|
| 419 | + |
|---|
| 420 | + if (__intel_wait_for_register_fw(uncore, |
|---|
| 421 | + GEN6_PCODE_MAILBOX, |
|---|
| 422 | + GEN6_PCODE_READY, 0, |
|---|
| 423 | + fast_timeout_us, |
|---|
| 424 | + slow_timeout_ms, |
|---|
| 425 | + &mbox)) |
|---|
| 426 | + return -ETIMEDOUT; |
|---|
| 427 | + |
|---|
| 428 | + if (is_read) |
|---|
| 429 | + *val = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA); |
|---|
| 430 | + if (is_read && val1) |
|---|
| 431 | + *val1 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA1); |
|---|
| 432 | + |
|---|
| 433 | + if (INTEL_GEN(i915) > 6) |
|---|
| 434 | + return gen7_check_mailbox_status(mbox); |
|---|
| 263 | 435 | else |
|---|
| 264 | | - tmp = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IOWR; |
|---|
| 265 | | - I915_WRITE(SBI_CTL_STAT, SBI_BUSY | tmp); |
|---|
| 266 | | - |
|---|
| 267 | | - if (intel_wait_for_register(dev_priv, |
|---|
| 268 | | - SBI_CTL_STAT, |
|---|
| 269 | | - SBI_BUSY, |
|---|
| 270 | | - 0, |
|---|
| 271 | | - 100)) { |
|---|
| 272 | | - DRM_ERROR("timeout waiting for SBI to complete write\n"); |
|---|
| 273 | | - return; |
|---|
| 274 | | - } |
|---|
| 275 | | - |
|---|
| 276 | | - if (I915_READ(SBI_CTL_STAT) & SBI_RESPONSE_FAIL) { |
|---|
| 277 | | - DRM_ERROR("error during SBI write of %x to reg %x\n", |
|---|
| 278 | | - value, reg); |
|---|
| 279 | | - return; |
|---|
| 280 | | - } |
|---|
| 436 | + return gen6_check_mailbox_status(mbox); |
|---|
| 281 | 437 | } |
|---|
| 282 | 438 | |
|---|
| 283 | | -u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg) |
|---|
| 439 | +int sandybridge_pcode_read(struct drm_i915_private *i915, u32 mbox, |
|---|
| 440 | + u32 *val, u32 *val1) |
|---|
| 284 | 441 | { |
|---|
| 285 | | - u32 val = 0; |
|---|
| 286 | | - vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRRDDA_NP, |
|---|
| 287 | | - reg, &val); |
|---|
| 288 | | - return val; |
|---|
| 442 | + int err; |
|---|
| 443 | + |
|---|
| 444 | + mutex_lock(&i915->sb_lock); |
|---|
| 445 | + err = __sandybridge_pcode_rw(i915, mbox, val, val1, |
|---|
| 446 | + 500, 20, |
|---|
| 447 | + true); |
|---|
| 448 | + mutex_unlock(&i915->sb_lock); |
|---|
| 449 | + |
|---|
| 450 | + if (err) { |
|---|
| 451 | + drm_dbg(&i915->drm, |
|---|
| 452 | + "warning: pcode (read from mbox %x) mailbox access failed for %ps: %d\n", |
|---|
| 453 | + mbox, __builtin_return_address(0), err); |
|---|
| 454 | + } |
|---|
| 455 | + |
|---|
| 456 | + return err; |
|---|
| 289 | 457 | } |
|---|
| 290 | 458 | |
|---|
| 291 | | -void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) |
|---|
| 459 | +int sandybridge_pcode_write_timeout(struct drm_i915_private *i915, |
|---|
| 460 | + u32 mbox, u32 val, |
|---|
| 461 | + int fast_timeout_us, |
|---|
| 462 | + int slow_timeout_ms) |
|---|
| 292 | 463 | { |
|---|
| 293 | | - vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRWRDA_NP, |
|---|
| 294 | | - reg, &val); |
|---|
| 464 | + int err; |
|---|
| 465 | + |
|---|
| 466 | + mutex_lock(&i915->sb_lock); |
|---|
| 467 | + err = __sandybridge_pcode_rw(i915, mbox, &val, NULL, |
|---|
| 468 | + fast_timeout_us, slow_timeout_ms, |
|---|
| 469 | + false); |
|---|
| 470 | + mutex_unlock(&i915->sb_lock); |
|---|
| 471 | + |
|---|
| 472 | + if (err) { |
|---|
| 473 | + drm_dbg(&i915->drm, |
|---|
| 474 | + "warning: pcode (write of 0x%08x to mbox %x) mailbox access failed for %ps: %d\n", |
|---|
| 475 | + val, mbox, __builtin_return_address(0), err); |
|---|
| 476 | + } |
|---|
| 477 | + |
|---|
| 478 | + return err; |
|---|
| 479 | +} |
|---|
| 480 | + |
|---|
| 481 | +static bool skl_pcode_try_request(struct drm_i915_private *i915, u32 mbox, |
|---|
| 482 | + u32 request, u32 reply_mask, u32 reply, |
|---|
| 483 | + u32 *status) |
|---|
| 484 | +{ |
|---|
| 485 | + *status = __sandybridge_pcode_rw(i915, mbox, &request, NULL, |
|---|
| 486 | + 500, 0, |
|---|
| 487 | + true); |
|---|
| 488 | + |
|---|
| 489 | + return *status || ((request & reply_mask) == reply); |
|---|
| 490 | +} |
|---|
| 491 | + |
|---|
| 492 | +/** |
|---|
| 493 | + * skl_pcode_request - send PCODE request until acknowledgment |
|---|
| 494 | + * @i915: device private |
|---|
| 495 | + * @mbox: PCODE mailbox ID the request is targeted for |
|---|
| 496 | + * @request: request ID |
|---|
| 497 | + * @reply_mask: mask used to check for request acknowledgment |
|---|
| 498 | + * @reply: value used to check for request acknowledgment |
|---|
| 499 | + * @timeout_base_ms: timeout for polling with preemption enabled |
|---|
| 500 | + * |
|---|
| 501 | + * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE |
|---|
| 502 | + * reports an error or an overall timeout of @timeout_base_ms+50 ms expires. |
|---|
| 503 | + * The request is acknowledged once the PCODE reply dword equals @reply after |
|---|
| 504 | + * applying @reply_mask. Polling is first attempted with preemption enabled |
|---|
| 505 | + * for @timeout_base_ms and if this times out for another 50 ms with |
|---|
| 506 | + * preemption disabled. |
|---|
| 507 | + * |
|---|
| 508 | + * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some |
|---|
| 509 | + * other error as reported by PCODE. |
|---|
| 510 | + */ |
|---|
| 511 | +int skl_pcode_request(struct drm_i915_private *i915, u32 mbox, u32 request, |
|---|
| 512 | + u32 reply_mask, u32 reply, int timeout_base_ms) |
|---|
| 513 | +{ |
|---|
| 514 | + u32 status; |
|---|
| 515 | + int ret; |
|---|
| 516 | + |
|---|
| 517 | + mutex_lock(&i915->sb_lock); |
|---|
| 518 | + |
|---|
| 519 | +#define COND \ |
|---|
| 520 | + skl_pcode_try_request(i915, mbox, request, reply_mask, reply, &status) |
|---|
| 521 | + |
|---|
| 522 | + /* |
|---|
| 523 | + * Prime the PCODE by doing a request first. Normally it guarantees |
|---|
| 524 | + * that a subsequent request, at most @timeout_base_ms later, succeeds. |
|---|
| 525 | + * _wait_for() doesn't guarantee when its passed condition is evaluated |
|---|
| 526 | + * first, so send the first request explicitly. |
|---|
| 527 | + */ |
|---|
| 528 | + if (COND) { |
|---|
| 529 | + ret = 0; |
|---|
| 530 | + goto out; |
|---|
| 531 | + } |
|---|
| 532 | + ret = _wait_for(COND, timeout_base_ms * 1000, 10, 10); |
|---|
| 533 | + if (!ret) |
|---|
| 534 | + goto out; |
|---|
| 535 | + |
|---|
| 536 | + /* |
|---|
| 537 | + * The above can time out if the number of requests was low (2 in the |
|---|
| 538 | + * worst case) _and_ PCODE was busy for some reason even after a |
|---|
| 539 | + * (queued) request and @timeout_base_ms delay. As a workaround retry |
|---|
| 540 | + * the poll with preemption disabled to maximize the number of |
|---|
| 541 | + * requests. Increase the timeout from @timeout_base_ms to 50ms to |
|---|
| 542 | + * account for interrupts that could reduce the number of these |
|---|
| 543 | + * requests, and for any quirks of the PCODE firmware that delays |
|---|
| 544 | + * the request completion. |
|---|
| 545 | + */ |
|---|
| 546 | + drm_dbg_kms(&i915->drm, |
|---|
| 547 | + "PCODE timeout, retrying with preemption disabled\n"); |
|---|
| 548 | + drm_WARN_ON_ONCE(&i915->drm, timeout_base_ms > 3); |
|---|
| 549 | + preempt_disable(); |
|---|
| 550 | + ret = wait_for_atomic(COND, 50); |
|---|
| 551 | + preempt_enable(); |
|---|
| 552 | + |
|---|
| 553 | +out: |
|---|
| 554 | + mutex_unlock(&i915->sb_lock); |
|---|
| 555 | + return ret ? ret : status; |
|---|
| 556 | +#undef COND |
|---|
| 557 | +} |
|---|
| 558 | + |
|---|
| 559 | +void intel_pcode_init(struct drm_i915_private *i915) |
|---|
| 560 | +{ |
|---|
| 561 | + int ret; |
|---|
| 562 | + |
|---|
| 563 | + if (!IS_DGFX(i915)) |
|---|
| 564 | + return; |
|---|
| 565 | + |
|---|
| 566 | + ret = skl_pcode_request(i915, DG1_PCODE_STATUS, |
|---|
| 567 | + DG1_UNCORE_GET_INIT_STATUS, |
|---|
| 568 | + DG1_UNCORE_INIT_STATUS_COMPLETE, |
|---|
| 569 | + DG1_UNCORE_INIT_STATUS_COMPLETE, 50); |
|---|
| 570 | + if (ret) |
|---|
| 571 | + drm_err(&i915->drm, "Pcode did not report uncore initialization completion!\n"); |
|---|
| 295 | 572 | } |
|---|