Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/i915/icl: Sanitize DDI port clock gating for DSI ports

The requirement for the DDI port clock gating for a port in DSI mode is
the opposite wrt. the case when the port is in DDI mode: the clock
should be gated when the port is active and ungated when the port is
inactive. Note that we cannot simply keep the DDI clock gated when the
port will be only used in DSI mode: it must be gated/ungated at a
specific spot in the DSI enable/disable sequence.

Ensure the above for all ports of a DSI encoder, also adding a sanity
check that we haven't registered another encoder using the same port
(VBT should never allow this to happen).

Cc: Madhav Chauhan <madhav.chauhan@intel.com>
Cc: Vandita Kulkarni <vandita.kulkarni@intel.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Clint Taylor <clinton.a.taylor@intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/ceb14d5a68e8e23988d923d4290a4f981789e616.1543500285.git.jani.nikula@intel.com

authored by

Imre Deak and committed by
Jani Nikula
1dd07e56 3b8c0d5b

+53 -17
+48 -17
drivers/gpu/drm/i915/intel_ddi.c
··· 28 28 #include <drm/drm_scdc_helper.h> 29 29 #include "i915_drv.h" 30 30 #include "intel_drv.h" 31 + #include "intel_dsi.h" 31 32 32 33 struct ddi_buf_trans { 33 34 u32 trans1; /* balance leg enable, de-emph level */ ··· 2837 2836 { 2838 2837 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 2839 2838 u32 val; 2840 - enum port port = encoder->port; 2841 - bool clk_enabled; 2839 + enum port port; 2840 + u32 port_mask; 2841 + bool ddi_clk_needed; 2842 2842 2843 2843 /* 2844 2844 * In case of DP MST, we sanitize the primary encoder only, not the ··· 2847 2845 */ 2848 2846 if (encoder->type == INTEL_OUTPUT_DP_MST) 2849 2847 return; 2850 - 2851 - val = I915_READ(DPCLKA_CFGCR0_ICL); 2852 - clk_enabled = !(val & icl_dpclka_cfgcr0_clk_off(dev_priv, port)); 2853 2848 2854 2849 if (!encoder->base.crtc && intel_encoder_is_dp(encoder)) { 2855 2850 u8 pipe_mask; ··· 2861 2862 return; 2862 2863 } 2863 2864 2864 - if (clk_enabled == !!encoder->base.crtc) 2865 - return; 2865 + port_mask = BIT(encoder->port); 2866 + ddi_clk_needed = encoder->base.crtc; 2866 2867 2867 - /* 2868 - * Punt on the case now where clock is disabled, but the encoder is 2869 - * enabled, something else is really broken then. 2870 - */ 2871 - if (WARN_ON(!clk_enabled)) 2872 - return; 2868 + if (encoder->type == INTEL_OUTPUT_DSI) { 2869 + struct intel_encoder *other_encoder; 2873 2870 2874 - DRM_NOTE("Port %c is disabled but it has a mapped PLL, unmap it\n", 2875 - port_name(port)); 2876 - val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port); 2877 - I915_WRITE(DPCLKA_CFGCR0_ICL, val); 2871 + port_mask = intel_dsi_encoder_ports(encoder); 2872 + /* 2873 + * Sanity check that we haven't incorrectly registered another 2874 + * encoder using any of the ports of this DSI encoder. 2875 + */ 2876 + for_each_intel_encoder(&dev_priv->drm, other_encoder) { 2877 + if (other_encoder == encoder) 2878 + continue; 2879 + 2880 + if (WARN_ON(port_mask & BIT(other_encoder->port))) 2881 + return; 2882 + } 2883 + /* 2884 + * DSI ports should have their DDI clock ungated when disabled 2885 + * and gated when enabled. 2886 + */ 2887 + ddi_clk_needed = !encoder->base.crtc; 2888 + } 2889 + 2890 + val = I915_READ(DPCLKA_CFGCR0_ICL); 2891 + for_each_port_masked(port, port_mask) { 2892 + bool ddi_clk_ungated = !(val & 2893 + icl_dpclka_cfgcr0_clk_off(dev_priv, 2894 + port)); 2895 + 2896 + if (ddi_clk_needed == ddi_clk_ungated) 2897 + continue; 2898 + 2899 + /* 2900 + * Punt on the case now where clock is gated, but it would 2901 + * be needed by the port. Something else is really broken then. 2902 + */ 2903 + if (WARN_ON(ddi_clk_needed)) 2904 + continue; 2905 + 2906 + DRM_NOTE("Port %c is disabled/in DSI mode with an ungated DDI clock, gate it\n", 2907 + port_name(port)); 2908 + val |= icl_dpclka_cfgcr0_clk_off(dev_priv, port); 2909 + I915_WRITE(DPCLKA_CFGCR0_ICL, val); 2910 + } 2878 2911 } 2879 2912 2880 2913 static void intel_ddi_clk_select(struct intel_encoder *encoder,
+5
drivers/gpu/drm/i915/intel_dsi.h
··· 146 146 return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE; 147 147 } 148 148 149 + static inline u16 intel_dsi_encoder_ports(struct intel_encoder *encoder) 150 + { 151 + return enc_to_intel_dsi(&encoder->base)->ports; 152 + } 153 + 149 154 /* intel_dsi.c */ 150 155 int intel_dsi_bitrate(const struct intel_dsi *intel_dsi); 151 156 int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi);