Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2013-2021 Intel Corporation
0004  */
0005 
0006 #include "i915_drv.h"
0007 #include "i915_iosf_mbi.h"
0008 #include "i915_reg.h"
0009 #include "vlv_sideband.h"
0010 
0011 /*
0012  * IOSF sideband, see VLV2_SidebandMsg_HAS.docx and
0013  * VLV_VLV2_PUNIT_HAS_0.8.docx
0014  */
0015 
0016 /* Standard MMIO read, non-posted */
0017 #define SB_MRD_NP   0x00
0018 /* Standard MMIO write, non-posted */
0019 #define SB_MWR_NP   0x01
0020 /* Private register read, double-word addressing, non-posted */
0021 #define SB_CRRDDA_NP    0x06
0022 /* Private register write, double-word addressing, non-posted */
0023 #define SB_CRWRDA_NP    0x07
0024 
0025 static void ping(void *info)
0026 {
0027 }
0028 
0029 static void __vlv_punit_get(struct drm_i915_private *i915)
0030 {
0031     iosf_mbi_punit_acquire();
0032 
0033     /*
0034      * Prevent the cpu from sleeping while we use this sideband, otherwise
0035      * the punit may cause a machine hang. The issue appears to be isolated
0036      * with changing the power state of the CPU package while changing
0037      * the power state via the punit, and we have only observed it
0038      * reliably on 4-core Baytail systems suggesting the issue is in the
0039      * power delivery mechanism and likely to be board/function
0040      * specific. Hence we presume the workaround needs only be applied
0041      * to the Valleyview P-unit and not all sideband communications.
0042      */
0043     if (IS_VALLEYVIEW(i915)) {
0044         cpu_latency_qos_update_request(&i915->sb_qos, 0);
0045         on_each_cpu(ping, NULL, 1);
0046     }
0047 }
0048 
0049 static void __vlv_punit_put(struct drm_i915_private *i915)
0050 {
0051     if (IS_VALLEYVIEW(i915))
0052         cpu_latency_qos_update_request(&i915->sb_qos,
0053                            PM_QOS_DEFAULT_VALUE);
0054 
0055     iosf_mbi_punit_release();
0056 }
0057 
0058 void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports)
0059 {
0060     if (ports & BIT(VLV_IOSF_SB_PUNIT))
0061         __vlv_punit_get(i915);
0062 
0063     mutex_lock(&i915->sb_lock);
0064 }
0065 
0066 void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports)
0067 {
0068     mutex_unlock(&i915->sb_lock);
0069 
0070     if (ports & BIT(VLV_IOSF_SB_PUNIT))
0071         __vlv_punit_put(i915);
0072 }
0073 
0074 static int vlv_sideband_rw(struct drm_i915_private *i915,
0075                u32 devfn, u32 port, u32 opcode,
0076                u32 addr, u32 *val)
0077 {
0078     struct intel_uncore *uncore = &i915->uncore;
0079     const bool is_read = (opcode == SB_MRD_NP || opcode == SB_CRRDDA_NP);
0080     int err;
0081 
0082     lockdep_assert_held(&i915->sb_lock);
0083     if (port == IOSF_PORT_PUNIT)
0084         iosf_mbi_assert_punit_acquired();
0085 
0086     /* Flush the previous comms, just in case it failed last time. */
0087     if (intel_wait_for_register(uncore,
0088                     VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0,
0089                     5)) {
0090         drm_dbg(&i915->drm, "IOSF sideband idle wait (%s) timed out\n",
0091             is_read ? "read" : "write");
0092         return -EAGAIN;
0093     }
0094 
0095     preempt_disable();
0096 
0097     intel_uncore_write_fw(uncore, VLV_IOSF_ADDR, addr);
0098     intel_uncore_write_fw(uncore, VLV_IOSF_DATA, is_read ? 0 : *val);
0099     intel_uncore_write_fw(uncore, VLV_IOSF_DOORBELL_REQ,
0100                   (devfn << IOSF_DEVFN_SHIFT) |
0101                   (opcode << IOSF_OPCODE_SHIFT) |
0102                   (port << IOSF_PORT_SHIFT) |
0103                   (0xf << IOSF_BYTE_ENABLES_SHIFT) |
0104                   (0 << IOSF_BAR_SHIFT) |
0105                   IOSF_SB_BUSY);
0106 
0107     if (__intel_wait_for_register_fw(uncore,
0108                      VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0,
0109                      10000, 0, NULL) == 0) {
0110         if (is_read)
0111             *val = intel_uncore_read_fw(uncore, VLV_IOSF_DATA);
0112         err = 0;
0113     } else {
0114         drm_dbg(&i915->drm, "IOSF sideband finish wait (%s) timed out\n",
0115             is_read ? "read" : "write");
0116         err = -ETIMEDOUT;
0117     }
0118 
0119     preempt_enable();
0120 
0121     return err;
0122 }
0123 
0124 u32 vlv_punit_read(struct drm_i915_private *i915, u32 addr)
0125 {
0126     u32 val = 0;
0127 
0128     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
0129             SB_CRRDDA_NP, addr, &val);
0130 
0131     return val;
0132 }
0133 
0134 int vlv_punit_write(struct drm_i915_private *i915, u32 addr, u32 val)
0135 {
0136     return vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
0137                    SB_CRWRDA_NP, addr, &val);
0138 }
0139 
0140 u32 vlv_bunit_read(struct drm_i915_private *i915, u32 reg)
0141 {
0142     u32 val = 0;
0143 
0144     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
0145             SB_CRRDDA_NP, reg, &val);
0146 
0147     return val;
0148 }
0149 
0150 void vlv_bunit_write(struct drm_i915_private *i915, u32 reg, u32 val)
0151 {
0152     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
0153             SB_CRWRDA_NP, reg, &val);
0154 }
0155 
0156 u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr)
0157 {
0158     u32 val = 0;
0159 
0160     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_NC,
0161             SB_CRRDDA_NP, addr, &val);
0162 
0163     return val;
0164 }
0165 
0166 u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg)
0167 {
0168     u32 val = 0;
0169 
0170     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port,
0171             SB_CRRDDA_NP, reg, &val);
0172 
0173     return val;
0174 }
0175 
0176 void vlv_iosf_sb_write(struct drm_i915_private *i915,
0177                u8 port, u32 reg, u32 val)
0178 {
0179     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port,
0180             SB_CRWRDA_NP, reg, &val);
0181 }
0182 
0183 u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg)
0184 {
0185     u32 val = 0;
0186 
0187     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
0188             SB_CRRDDA_NP, reg, &val);
0189 
0190     return val;
0191 }
0192 
0193 void vlv_cck_write(struct drm_i915_private *i915, u32 reg, u32 val)
0194 {
0195     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
0196             SB_CRWRDA_NP, reg, &val);
0197 }
0198 
0199 u32 vlv_ccu_read(struct drm_i915_private *i915, u32 reg)
0200 {
0201     u32 val = 0;
0202 
0203     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
0204             SB_CRRDDA_NP, reg, &val);
0205 
0206     return val;
0207 }
0208 
0209 void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val)
0210 {
0211     vlv_sideband_rw(i915, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
0212             SB_CRWRDA_NP, reg, &val);
0213 }
0214 
0215 static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy phy)
0216 {
0217     /*
0218      * IOSF_PORT_DPIO: VLV x2 PHY (DP/HDMI B and C), CHV x1 PHY (DP/HDMI D)
0219      * IOSF_PORT_DPIO_2: CHV x2 PHY (DP/HDMI B and C)
0220      */
0221     if (IS_CHERRYVIEW(i915))
0222         return phy == DPIO_PHY0 ? IOSF_PORT_DPIO_2 : IOSF_PORT_DPIO;
0223     else
0224         return IOSF_PORT_DPIO;
0225 }
0226 
0227 u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg)
0228 {
0229     u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe));
0230     u32 val = 0;
0231 
0232     vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val);
0233 
0234     /*
0235      * FIXME: There might be some registers where all 1's is a valid value,
0236      * so ideally we should check the register offset instead...
0237      */
0238     drm_WARN(&i915->drm, val == 0xffffffff,
0239          "DPIO read pipe %c reg 0x%x == 0x%x\n",
0240          pipe_name(pipe), reg, val);
0241 
0242     return val;
0243 }
0244 
0245 void vlv_dpio_write(struct drm_i915_private *i915,
0246             enum pipe pipe, int reg, u32 val)
0247 {
0248     u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe));
0249 
0250     vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val);
0251 }
0252 
0253 u32 vlv_flisdsi_read(struct drm_i915_private *i915, u32 reg)
0254 {
0255     u32 val = 0;
0256 
0257     vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRRDDA_NP,
0258             reg, &val);
0259     return val;
0260 }
0261 
0262 void vlv_flisdsi_write(struct drm_i915_private *i915, u32 reg, u32 val)
0263 {
0264     vlv_sideband_rw(i915, DPIO_DEVFN, IOSF_PORT_FLISDSI, SB_CRWRDA_NP,
0265             reg, &val);
0266 }