On Fri, Oct 15, 2021 at 5:16 PM Ville Syrjala <ville.syrjala@xxxxxxxxxxxxxxx> wrote: > > From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > Start moving the code for PCH modeset sequence/etc. to > its own file. > > Still not sure about the file name though... Name is good enough for now, there aren't a lot of great names, no point getting stuck on it. Otherwise Reviewed-by: Dave Airlie <airlied@xxxxxxxxxx> > > Cc: Dave Airlie <airlied@xxxxxxxxxx> > Cc: Jani Nikula <jani.nikula@xxxxxxxxx> > Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/i915/Makefile | 1 + > drivers/gpu/drm/i915/display/intel_crt.c | 1 + > drivers/gpu/drm/i915/display/intel_display.c | 348 +---------------- > drivers/gpu/drm/i915/display/intel_display.h | 5 - > .../gpu/drm/i915/display/intel_pch_display.c | 365 ++++++++++++++++++ > .../gpu/drm/i915/display/intel_pch_display.h | 22 ++ > 6 files changed, 390 insertions(+), 352 deletions(-) > create mode 100644 drivers/gpu/drm/i915/display/intel_pch_display.c > create mode 100644 drivers/gpu/drm/i915/display/intel_pch_display.h > > diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile > index 96f3b8f6c50d..467872cca027 100644 > --- a/drivers/gpu/drm/i915/Makefile > +++ b/drivers/gpu/drm/i915/Makefile > @@ -226,6 +226,7 @@ i915-y += \ > display/intel_hotplug.o \ > display/intel_lpe_audio.o \ > display/intel_overlay.o \ > + display/intel_pch_display.o \ > display/intel_pch_refclk.o \ > display/intel_plane_initial.o \ > display/intel_psr.o \ > diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c > index bf03bd0ecd43..54540138bd1d 100644 > --- a/drivers/gpu/drm/i915/display/intel_crt.c > +++ b/drivers/gpu/drm/i915/display/intel_crt.c > @@ -45,6 +45,7 @@ > #include "intel_fifo_underrun.h" > #include "intel_gmbus.h" > #include "intel_hotplug.h" > +#include "intel_pch_display.h" > #include "intel_pch_refclk.h" > > /* Here's the desired hotplug mode */ > diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c > index 995050443065..69549886fe5b 100644 > --- a/drivers/gpu/drm/i915/display/intel_display.c > +++ b/drivers/gpu/drm/i915/display/intel_display.c > @@ -96,6 +96,7 @@ > #include "intel_hotplug.h" > #include "intel_overlay.h" > #include "intel_panel.h" > +#include "intel_pch_display.h" > #include "intel_pch_refclk.h" > #include "intel_pcode.h" > #include "intel_pipe_crc.h" > @@ -454,80 +455,6 @@ static void assert_planes_disabled(struct intel_crtc *crtc) > assert_plane_disabled(plane); > } > > -void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, > - enum pipe pipe) > -{ > - u32 val; > - bool enabled; > - > - val = intel_de_read(dev_priv, PCH_TRANSCONF(pipe)); > - enabled = !!(val & TRANS_ENABLE); > - I915_STATE_WARN(enabled, > - "transcoder assertion failed, should be off on pipe %c but is still active\n", > - pipe_name(pipe)); > -} > - > -static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, > - enum pipe pipe, enum port port, > - i915_reg_t dp_reg) > -{ > - enum pipe port_pipe; > - bool state; > - > - state = g4x_dp_port_enabled(dev_priv, dp_reg, port, &port_pipe); > - > - I915_STATE_WARN(state && port_pipe == pipe, > - "PCH DP %c enabled on transcoder %c, should be disabled\n", > - port_name(port), pipe_name(pipe)); > - > - I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B, > - "IBX PCH DP %c still using transcoder B\n", > - port_name(port)); > -} > - > -static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, > - enum pipe pipe, enum port port, > - i915_reg_t hdmi_reg) > -{ > - enum pipe port_pipe; > - bool state; > - > - state = intel_sdvo_port_enabled(dev_priv, hdmi_reg, &port_pipe); > - > - I915_STATE_WARN(state && port_pipe == pipe, > - "PCH HDMI %c enabled on transcoder %c, should be disabled\n", > - port_name(port), pipe_name(pipe)); > - > - I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B, > - "IBX PCH HDMI %c still using transcoder B\n", > - port_name(port)); > -} > - > -static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, > - enum pipe pipe) > -{ > - enum pipe port_pipe; > - > - assert_pch_dp_disabled(dev_priv, pipe, PORT_B, PCH_DP_B); > - assert_pch_dp_disabled(dev_priv, pipe, PORT_C, PCH_DP_C); > - assert_pch_dp_disabled(dev_priv, pipe, PORT_D, PCH_DP_D); > - > - I915_STATE_WARN(intel_crt_port_enabled(dev_priv, PCH_ADPA, &port_pipe) && > - port_pipe == pipe, > - "PCH VGA enabled on transcoder %c, should be disabled\n", > - pipe_name(pipe)); > - > - I915_STATE_WARN(intel_lvds_port_enabled(dev_priv, PCH_LVDS, &port_pipe) && > - port_pipe == pipe, > - "PCH LVDS enabled on transcoder %c, should be disabled\n", > - pipe_name(pipe)); > - > - /* PCH SDVOB multiplex with HDMIB */ > - assert_pch_hdmi_disabled(dev_priv, pipe, PORT_B, PCH_HDMIB); > - assert_pch_hdmi_disabled(dev_priv, pipe, PORT_C, PCH_HDMIC); > - assert_pch_hdmi_disabled(dev_priv, pipe, PORT_D, PCH_HDMID); > -} > - > void vlv_wait_port_ready(struct drm_i915_private *dev_priv, > struct intel_digital_port *dig_port, > unsigned int expected_mask) > @@ -562,154 +489,6 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, > expected_mask); > } > > -static void ilk_enable_pch_transcoder(const struct intel_crtc_state *crtc_state) > -{ > - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); > - enum pipe pipe = crtc->pipe; > - i915_reg_t reg; > - u32 val, pipeconf_val; > - > - /* Make sure PCH DPLL is enabled */ > - assert_shared_dpll_enabled(dev_priv, crtc_state->shared_dpll); > - > - /* FDI must be feeding us bits for PCH ports */ > - assert_fdi_tx_enabled(dev_priv, pipe); > - assert_fdi_rx_enabled(dev_priv, pipe); > - > - if (HAS_PCH_CPT(dev_priv)) { > - reg = TRANS_CHICKEN2(pipe); > - val = intel_de_read(dev_priv, reg); > - /* > - * Workaround: Set the timing override bit > - * before enabling the pch transcoder. > - */ > - val |= TRANS_CHICKEN2_TIMING_OVERRIDE; > - /* Configure frame start delay to match the CPU */ > - val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; > - val |= TRANS_CHICKEN2_FRAME_START_DELAY(dev_priv->framestart_delay - 1); > - intel_de_write(dev_priv, reg, val); > - } > - > - reg = PCH_TRANSCONF(pipe); > - val = intel_de_read(dev_priv, reg); > - pipeconf_val = intel_de_read(dev_priv, PIPECONF(pipe)); > - > - if (HAS_PCH_IBX(dev_priv)) { > - /* Configure frame start delay to match the CPU */ > - val &= ~TRANS_FRAME_START_DELAY_MASK; > - val |= TRANS_FRAME_START_DELAY(dev_priv->framestart_delay - 1); > - > - /* > - * Make the BPC in transcoder be consistent with > - * that in pipeconf reg. For HDMI we must use 8bpc > - * here for both 8bpc and 12bpc. > - */ > - val &= ~PIPECONF_BPC_MASK; > - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) > - val |= PIPECONF_8BPC; > - else > - val |= pipeconf_val & PIPECONF_BPC_MASK; > - } > - > - val &= ~TRANS_INTERLACE_MASK; > - if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK) { > - if (HAS_PCH_IBX(dev_priv) && > - intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO)) > - val |= TRANS_LEGACY_INTERLACED_ILK; > - else > - val |= TRANS_INTERLACED; > - } else { > - val |= TRANS_PROGRESSIVE; > - } > - > - intel_de_write(dev_priv, reg, val | TRANS_ENABLE); > - if (intel_de_wait_for_set(dev_priv, reg, TRANS_STATE_ENABLE, 100)) > - drm_err(&dev_priv->drm, "failed to enable transcoder %c\n", > - pipe_name(pipe)); > -} > - > -static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, > - enum transcoder cpu_transcoder) > -{ > - u32 val, pipeconf_val; > - > - /* FDI must be feeding us bits for PCH ports */ > - assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder); > - assert_fdi_rx_enabled(dev_priv, PIPE_A); > - > - val = intel_de_read(dev_priv, TRANS_CHICKEN2(PIPE_A)); > - /* Workaround: set timing override bit. */ > - val |= TRANS_CHICKEN2_TIMING_OVERRIDE; > - /* Configure frame start delay to match the CPU */ > - val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; > - val |= TRANS_CHICKEN2_FRAME_START_DELAY(dev_priv->framestart_delay - 1); > - intel_de_write(dev_priv, TRANS_CHICKEN2(PIPE_A), val); > - > - val = TRANS_ENABLE; > - pipeconf_val = intel_de_read(dev_priv, PIPECONF(cpu_transcoder)); > - > - if ((pipeconf_val & PIPECONF_INTERLACE_MASK_HSW) == > - PIPECONF_INTERLACED_ILK) > - val |= TRANS_INTERLACED; > - else > - val |= TRANS_PROGRESSIVE; > - > - intel_de_write(dev_priv, LPT_TRANSCONF, val); > - if (intel_de_wait_for_set(dev_priv, LPT_TRANSCONF, > - TRANS_STATE_ENABLE, 100)) > - drm_err(&dev_priv->drm, "Failed to enable PCH transcoder\n"); > -} > - > -static void ilk_disable_pch_transcoder(struct drm_i915_private *dev_priv, > - enum pipe pipe) > -{ > - i915_reg_t reg; > - u32 val; > - > - /* FDI relies on the transcoder */ > - assert_fdi_tx_disabled(dev_priv, pipe); > - assert_fdi_rx_disabled(dev_priv, pipe); > - > - /* Ports must be off as well */ > - assert_pch_ports_disabled(dev_priv, pipe); > - > - reg = PCH_TRANSCONF(pipe); > - val = intel_de_read(dev_priv, reg); > - val &= ~TRANS_ENABLE; > - intel_de_write(dev_priv, reg, val); > - /* wait for PCH transcoder off, transcoder state */ > - if (intel_de_wait_for_clear(dev_priv, reg, TRANS_STATE_ENABLE, 50)) > - drm_err(&dev_priv->drm, "failed to disable transcoder %c\n", > - pipe_name(pipe)); > - > - if (HAS_PCH_CPT(dev_priv)) { > - /* Workaround: Clear the timing override chicken bit again. */ > - reg = TRANS_CHICKEN2(pipe); > - val = intel_de_read(dev_priv, reg); > - val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; > - intel_de_write(dev_priv, reg, val); > - } > -} > - > -void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv) > -{ > - u32 val; > - > - val = intel_de_read(dev_priv, LPT_TRANSCONF); > - val &= ~TRANS_ENABLE; > - intel_de_write(dev_priv, LPT_TRANSCONF, val); > - /* wait for PCH transcoder off, transcoder state */ > - if (intel_de_wait_for_clear(dev_priv, LPT_TRANSCONF, > - TRANS_STATE_ENABLE, 50)) > - drm_err(&dev_priv->drm, "Failed to disable PCH transcoder\n"); > - > - /* Workaround: clear timing override bit. */ > - val = intel_de_read(dev_priv, TRANS_CHICKEN2(PIPE_A)); > - val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; > - intel_de_write(dev_priv, TRANS_CHICKEN2(PIPE_A), val); > -} > - > enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc) > { > struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); > @@ -1388,31 +1167,6 @@ bool intel_has_pending_fb_unpin(struct drm_i915_private *dev_priv) > return false; > } > > - > -static void ilk_pch_transcoder_set_timings(const struct intel_crtc_state *crtc_state, > - enum pipe pch_transcoder) > -{ > - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); > - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; > - > - intel_de_write(dev_priv, PCH_TRANS_HTOTAL(pch_transcoder), > - intel_de_read(dev_priv, HTOTAL(cpu_transcoder))); > - intel_de_write(dev_priv, PCH_TRANS_HBLANK(pch_transcoder), > - intel_de_read(dev_priv, HBLANK(cpu_transcoder))); > - intel_de_write(dev_priv, PCH_TRANS_HSYNC(pch_transcoder), > - intel_de_read(dev_priv, HSYNC(cpu_transcoder))); > - > - intel_de_write(dev_priv, PCH_TRANS_VTOTAL(pch_transcoder), > - intel_de_read(dev_priv, VTOTAL(cpu_transcoder))); > - intel_de_write(dev_priv, PCH_TRANS_VBLANK(pch_transcoder), > - intel_de_read(dev_priv, VBLANK(cpu_transcoder))); > - intel_de_write(dev_priv, PCH_TRANS_VSYNC(pch_transcoder), > - intel_de_read(dev_priv, VSYNC(cpu_transcoder))); > - intel_de_write(dev_priv, PCH_TRANS_VSYNCSHIFT(pch_transcoder), > - intel_de_read(dev_priv, VSYNCSHIFT(cpu_transcoder))); > -} > - > /* > * Finds the encoder associated with the given CRTC. This can only be > * used when we know that the CRTC isn't feeding multiple encoders! > @@ -1443,106 +1197,6 @@ intel_get_crtc_new_encoder(const struct intel_atomic_state *state, > return encoder; > } > > -/* > - * Enable PCH resources required for PCH ports: > - * - PCH PLLs > - * - FDI training & RX/TX > - * - update transcoder timings > - * - DP transcoding bits > - * - transcoder > - */ > -static void ilk_pch_enable(const struct intel_atomic_state *state, > - const struct intel_crtc_state *crtc_state) > -{ > - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > - struct drm_device *dev = crtc->base.dev; > - struct drm_i915_private *dev_priv = to_i915(dev); > - enum pipe pipe = crtc->pipe; > - u32 temp; > - > - assert_pch_transcoder_disabled(dev_priv, pipe); > - > - /* For PCH output, training FDI link */ > - intel_fdi_link_train(crtc, crtc_state); > - > - /* We need to program the right clock selection before writing the pixel > - * mutliplier into the DPLL. */ > - if (HAS_PCH_CPT(dev_priv)) { > - u32 sel; > - > - temp = intel_de_read(dev_priv, PCH_DPLL_SEL); > - temp |= TRANS_DPLL_ENABLE(pipe); > - sel = TRANS_DPLLB_SEL(pipe); > - if (crtc_state->shared_dpll == > - intel_get_shared_dpll_by_id(dev_priv, DPLL_ID_PCH_PLL_B)) > - temp |= sel; > - else > - temp &= ~sel; > - intel_de_write(dev_priv, PCH_DPLL_SEL, temp); > - } > - > - /* XXX: pch pll's can be enabled any time before we enable the PCH > - * transcoder, and we actually should do this to not upset any PCH > - * transcoder that already use the clock when we share it. > - * > - * Note that enable_shared_dpll tries to do the right thing, but > - * get_shared_dpll unconditionally resets the pll - we need that to have > - * the right LVDS enable sequence. */ > - intel_enable_shared_dpll(crtc_state); > - > - /* set transcoder timing, panel must allow it */ > - assert_pps_unlocked(dev_priv, pipe); > - ilk_pch_transcoder_set_timings(crtc_state, pipe); > - > - intel_fdi_normal_train(crtc); > - > - /* For PCH DP, enable TRANS_DP_CTL */ > - if (HAS_PCH_CPT(dev_priv) && > - intel_crtc_has_dp_encoder(crtc_state)) { > - const struct drm_display_mode *adjusted_mode = > - &crtc_state->hw.adjusted_mode; > - u32 bpc = (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5; > - i915_reg_t reg = TRANS_DP_CTL(pipe); > - enum port port; > - > - temp = intel_de_read(dev_priv, reg); > - temp &= ~(TRANS_DP_PORT_SEL_MASK | > - TRANS_DP_SYNC_MASK | > - TRANS_DP_BPC_MASK); > - temp |= TRANS_DP_OUTPUT_ENABLE; > - temp |= bpc << 9; /* same format but at 11:9 */ > - > - if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) > - temp |= TRANS_DP_HSYNC_ACTIVE_HIGH; > - if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) > - temp |= TRANS_DP_VSYNC_ACTIVE_HIGH; > - > - port = intel_get_crtc_new_encoder(state, crtc_state)->port; > - drm_WARN_ON(dev, port < PORT_B || port > PORT_D); > - temp |= TRANS_DP_PORT_SEL(port); > - > - intel_de_write(dev_priv, reg, temp); > - } > - > - ilk_enable_pch_transcoder(crtc_state); > -} > - > -void lpt_pch_enable(const struct intel_crtc_state *crtc_state) > -{ > - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); > - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; > - > - assert_pch_transcoder_disabled(dev_priv, PIPE_A); > - > - lpt_program_iclkip(crtc_state); > - > - /* Set transcoder timing. */ > - ilk_pch_transcoder_set_timings(crtc_state, PIPE_A); > - > - lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); > -} > - > static void cpt_verify_modeset(struct drm_i915_private *dev_priv, > enum pipe pipe) > { > diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h > index 39c18b8807f9..93c84f2174b5 100644 > --- a/drivers/gpu/drm/i915/display/intel_display.h > +++ b/drivers/gpu/drm/i915/display/intel_display.h > @@ -541,8 +541,6 @@ int vlv_get_cck_clock(struct drm_i915_private *dev_priv, > const char *name, u32 reg, int ref_freq); > int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv, > const char *name, u32 reg); > -void lpt_pch_enable(const struct intel_crtc_state *crtc_state); > -void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv); > void intel_init_display_hooks(struct drm_i915_private *dev_priv); > unsigned int intel_fb_xy_to_linear(int x, int y, > const struct intel_plane_state *state, > @@ -578,9 +576,6 @@ struct drm_framebuffer * > intel_framebuffer_create(struct drm_i915_gem_object *obj, > struct drm_mode_fb_cmd2 *mode_cmd); > > -void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, > - enum pipe pipe); > - > bool intel_fuzzy_clock_check(int clock1, int clock2); > > void intel_display_prepare_reset(struct drm_i915_private *dev_priv); > diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.c b/drivers/gpu/drm/i915/display/intel_pch_display.c > new file mode 100644 > index 000000000000..0056c2fe49ec > --- /dev/null > +++ b/drivers/gpu/drm/i915/display/intel_pch_display.c > @@ -0,0 +1,365 @@ > +// SPDX-License-Identifier: MIT > +/* > + * Copyright © 2021 Intel Corporation > + */ > + > +#include "g4x_dp.h" > +#include "intel_crt.h" > +#include "intel_de.h" > +#include "intel_display_types.h" > +#include "intel_fdi.h" > +#include "intel_lvds.h" > +#include "intel_pch_display.h" > +#include "intel_pch_refclk.h" > +#include "intel_pps.h" > +#include "intel_sdvo.h" > + > +static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, > + enum pipe pipe, enum port port, > + i915_reg_t dp_reg) > +{ > + enum pipe port_pipe; > + bool state; > + > + state = g4x_dp_port_enabled(dev_priv, dp_reg, port, &port_pipe); > + > + I915_STATE_WARN(state && port_pipe == pipe, > + "PCH DP %c enabled on transcoder %c, should be disabled\n", > + port_name(port), pipe_name(pipe)); > + > + I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B, > + "IBX PCH DP %c still using transcoder B\n", > + port_name(port)); > +} > + > +static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, > + enum pipe pipe, enum port port, > + i915_reg_t hdmi_reg) > +{ > + enum pipe port_pipe; > + bool state; > + > + state = intel_sdvo_port_enabled(dev_priv, hdmi_reg, &port_pipe); > + > + I915_STATE_WARN(state && port_pipe == pipe, > + "PCH HDMI %c enabled on transcoder %c, should be disabled\n", > + port_name(port), pipe_name(pipe)); > + > + I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B, > + "IBX PCH HDMI %c still using transcoder B\n", > + port_name(port)); > +} > + > +static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, > + enum pipe pipe) > +{ > + enum pipe port_pipe; > + > + assert_pch_dp_disabled(dev_priv, pipe, PORT_B, PCH_DP_B); > + assert_pch_dp_disabled(dev_priv, pipe, PORT_C, PCH_DP_C); > + assert_pch_dp_disabled(dev_priv, pipe, PORT_D, PCH_DP_D); > + > + I915_STATE_WARN(intel_crt_port_enabled(dev_priv, PCH_ADPA, &port_pipe) && > + port_pipe == pipe, > + "PCH VGA enabled on transcoder %c, should be disabled\n", > + pipe_name(pipe)); > + > + I915_STATE_WARN(intel_lvds_port_enabled(dev_priv, PCH_LVDS, &port_pipe) && > + port_pipe == pipe, > + "PCH LVDS enabled on transcoder %c, should be disabled\n", > + pipe_name(pipe)); > + > + /* PCH SDVOB multiplex with HDMIB */ > + assert_pch_hdmi_disabled(dev_priv, pipe, PORT_B, PCH_HDMIB); > + assert_pch_hdmi_disabled(dev_priv, pipe, PORT_C, PCH_HDMIC); > + assert_pch_hdmi_disabled(dev_priv, pipe, PORT_D, PCH_HDMID); > +} > + > +static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, > + enum pipe pipe) > +{ > + u32 val; > + bool enabled; > + > + val = intel_de_read(dev_priv, PCH_TRANSCONF(pipe)); > + enabled = !!(val & TRANS_ENABLE); > + I915_STATE_WARN(enabled, > + "transcoder assertion failed, should be off on pipe %c but is still active\n", > + pipe_name(pipe)); > +} > + > +static void ilk_pch_transcoder_set_timings(const struct intel_crtc_state *crtc_state, > + enum pipe pch_transcoder) > +{ > + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); > + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; > + > + intel_de_write(dev_priv, PCH_TRANS_HTOTAL(pch_transcoder), > + intel_de_read(dev_priv, HTOTAL(cpu_transcoder))); > + intel_de_write(dev_priv, PCH_TRANS_HBLANK(pch_transcoder), > + intel_de_read(dev_priv, HBLANK(cpu_transcoder))); > + intel_de_write(dev_priv, PCH_TRANS_HSYNC(pch_transcoder), > + intel_de_read(dev_priv, HSYNC(cpu_transcoder))); > + > + intel_de_write(dev_priv, PCH_TRANS_VTOTAL(pch_transcoder), > + intel_de_read(dev_priv, VTOTAL(cpu_transcoder))); > + intel_de_write(dev_priv, PCH_TRANS_VBLANK(pch_transcoder), > + intel_de_read(dev_priv, VBLANK(cpu_transcoder))); > + intel_de_write(dev_priv, PCH_TRANS_VSYNC(pch_transcoder), > + intel_de_read(dev_priv, VSYNC(cpu_transcoder))); > + intel_de_write(dev_priv, PCH_TRANS_VSYNCSHIFT(pch_transcoder), > + intel_de_read(dev_priv, VSYNCSHIFT(cpu_transcoder))); > +} > + > +static void ilk_enable_pch_transcoder(const struct intel_crtc_state *crtc_state) > +{ > + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); > + enum pipe pipe = crtc->pipe; > + i915_reg_t reg; > + u32 val, pipeconf_val; > + > + /* Make sure PCH DPLL is enabled */ > + assert_shared_dpll_enabled(dev_priv, crtc_state->shared_dpll); > + > + /* FDI must be feeding us bits for PCH ports */ > + assert_fdi_tx_enabled(dev_priv, pipe); > + assert_fdi_rx_enabled(dev_priv, pipe); > + > + if (HAS_PCH_CPT(dev_priv)) { > + reg = TRANS_CHICKEN2(pipe); > + val = intel_de_read(dev_priv, reg); > + /* > + * Workaround: Set the timing override bit > + * before enabling the pch transcoder. > + */ > + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; > + /* Configure frame start delay to match the CPU */ > + val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; > + val |= TRANS_CHICKEN2_FRAME_START_DELAY(dev_priv->framestart_delay - 1); > + intel_de_write(dev_priv, reg, val); > + } > + > + reg = PCH_TRANSCONF(pipe); > + val = intel_de_read(dev_priv, reg); > + pipeconf_val = intel_de_read(dev_priv, PIPECONF(pipe)); > + > + if (HAS_PCH_IBX(dev_priv)) { > + /* Configure frame start delay to match the CPU */ > + val &= ~TRANS_FRAME_START_DELAY_MASK; > + val |= TRANS_FRAME_START_DELAY(dev_priv->framestart_delay - 1); > + > + /* > + * Make the BPC in transcoder be consistent with > + * that in pipeconf reg. For HDMI we must use 8bpc > + * here for both 8bpc and 12bpc. > + */ > + val &= ~PIPECONF_BPC_MASK; > + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) > + val |= PIPECONF_8BPC; > + else > + val |= pipeconf_val & PIPECONF_BPC_MASK; > + } > + > + val &= ~TRANS_INTERLACE_MASK; > + if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK) { > + if (HAS_PCH_IBX(dev_priv) && > + intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO)) > + val |= TRANS_LEGACY_INTERLACED_ILK; > + else > + val |= TRANS_INTERLACED; > + } else { > + val |= TRANS_PROGRESSIVE; > + } > + > + intel_de_write(dev_priv, reg, val | TRANS_ENABLE); > + if (intel_de_wait_for_set(dev_priv, reg, TRANS_STATE_ENABLE, 100)) > + drm_err(&dev_priv->drm, "failed to enable transcoder %c\n", > + pipe_name(pipe)); > +} > + > +void ilk_disable_pch_transcoder(struct drm_i915_private *dev_priv, > + enum pipe pipe) > +{ > + i915_reg_t reg; > + u32 val; > + > + /* FDI relies on the transcoder */ > + assert_fdi_tx_disabled(dev_priv, pipe); > + assert_fdi_rx_disabled(dev_priv, pipe); > + > + /* Ports must be off as well */ > + assert_pch_ports_disabled(dev_priv, pipe); > + > + reg = PCH_TRANSCONF(pipe); > + val = intel_de_read(dev_priv, reg); > + val &= ~TRANS_ENABLE; > + intel_de_write(dev_priv, reg, val); > + /* wait for PCH transcoder off, transcoder state */ > + if (intel_de_wait_for_clear(dev_priv, reg, TRANS_STATE_ENABLE, 50)) > + drm_err(&dev_priv->drm, "failed to disable transcoder %c\n", > + pipe_name(pipe)); > + > + if (HAS_PCH_CPT(dev_priv)) { > + /* Workaround: Clear the timing override chicken bit again. */ > + reg = TRANS_CHICKEN2(pipe); > + val = intel_de_read(dev_priv, reg); > + val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; > + intel_de_write(dev_priv, reg, val); > + } > +} > + > +/* > + * Enable PCH resources required for PCH ports: > + * - PCH PLLs > + * - FDI training & RX/TX > + * - update transcoder timings > + * - DP transcoding bits > + * - transcoder > + */ > +void ilk_pch_enable(const struct intel_atomic_state *state, > + const struct intel_crtc_state *crtc_state) > +{ > + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > + struct drm_device *dev = crtc->base.dev; > + struct drm_i915_private *dev_priv = to_i915(dev); > + enum pipe pipe = crtc->pipe; > + u32 temp; > + > + assert_pch_transcoder_disabled(dev_priv, pipe); > + > + /* For PCH output, training FDI link */ > + intel_fdi_link_train(crtc, crtc_state); > + > + /* > + * We need to program the right clock selection > + * before writing the pixel multiplier into the DPLL. > + */ > + if (HAS_PCH_CPT(dev_priv)) { > + u32 sel; > + > + temp = intel_de_read(dev_priv, PCH_DPLL_SEL); > + temp |= TRANS_DPLL_ENABLE(pipe); > + sel = TRANS_DPLLB_SEL(pipe); > + if (crtc_state->shared_dpll == > + intel_get_shared_dpll_by_id(dev_priv, DPLL_ID_PCH_PLL_B)) > + temp |= sel; > + else > + temp &= ~sel; > + intel_de_write(dev_priv, PCH_DPLL_SEL, temp); > + } > + > + /* > + * XXX: pch pll's can be enabled any time before we enable the PCH > + * transcoder, and we actually should do this to not upset any PCH > + * transcoder that already use the clock when we share it. > + * > + * Note that enable_shared_dpll tries to do the right thing, but > + * get_shared_dpll unconditionally resets the pll - we need that > + * to have the right LVDS enable sequence. > + */ > + intel_enable_shared_dpll(crtc_state); > + > + /* set transcoder timing, panel must allow it */ > + assert_pps_unlocked(dev_priv, pipe); > + ilk_pch_transcoder_set_timings(crtc_state, pipe); > + > + intel_fdi_normal_train(crtc); > + > + /* For PCH DP, enable TRANS_DP_CTL */ > + if (HAS_PCH_CPT(dev_priv) && > + intel_crtc_has_dp_encoder(crtc_state)) { > + const struct drm_display_mode *adjusted_mode = > + &crtc_state->hw.adjusted_mode; > + u32 bpc = (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5; > + i915_reg_t reg = TRANS_DP_CTL(pipe); > + enum port port; > + > + temp = intel_de_read(dev_priv, reg); > + temp &= ~(TRANS_DP_PORT_SEL_MASK | > + TRANS_DP_SYNC_MASK | > + TRANS_DP_BPC_MASK); > + temp |= TRANS_DP_OUTPUT_ENABLE; > + temp |= bpc << 9; /* same format but at 11:9 */ > + > + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) > + temp |= TRANS_DP_HSYNC_ACTIVE_HIGH; > + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) > + temp |= TRANS_DP_VSYNC_ACTIVE_HIGH; > + > + port = intel_get_crtc_new_encoder(state, crtc_state)->port; > + drm_WARN_ON(dev, port < PORT_B || port > PORT_D); > + temp |= TRANS_DP_PORT_SEL(port); > + > + intel_de_write(dev_priv, reg, temp); > + } > + > + ilk_enable_pch_transcoder(crtc_state); > +} > + > +static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, > + enum transcoder cpu_transcoder) > +{ > + u32 val, pipeconf_val; > + > + /* FDI must be feeding us bits for PCH ports */ > + assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder); > + assert_fdi_rx_enabled(dev_priv, PIPE_A); > + > + val = intel_de_read(dev_priv, TRANS_CHICKEN2(PIPE_A)); > + /* Workaround: set timing override bit. */ > + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; > + /* Configure frame start delay to match the CPU */ > + val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; > + val |= TRANS_CHICKEN2_FRAME_START_DELAY(dev_priv->framestart_delay - 1); > + intel_de_write(dev_priv, TRANS_CHICKEN2(PIPE_A), val); > + > + val = TRANS_ENABLE; > + pipeconf_val = intel_de_read(dev_priv, PIPECONF(cpu_transcoder)); > + > + if ((pipeconf_val & PIPECONF_INTERLACE_MASK_HSW) == > + PIPECONF_INTERLACED_ILK) > + val |= TRANS_INTERLACED; > + else > + val |= TRANS_PROGRESSIVE; > + > + intel_de_write(dev_priv, LPT_TRANSCONF, val); > + if (intel_de_wait_for_set(dev_priv, LPT_TRANSCONF, > + TRANS_STATE_ENABLE, 100)) > + drm_err(&dev_priv->drm, "Failed to enable PCH transcoder\n"); > +} > + > +void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv) > +{ > + u32 val; > + > + val = intel_de_read(dev_priv, LPT_TRANSCONF); > + val &= ~TRANS_ENABLE; > + intel_de_write(dev_priv, LPT_TRANSCONF, val); > + /* wait for PCH transcoder off, transcoder state */ > + if (intel_de_wait_for_clear(dev_priv, LPT_TRANSCONF, > + TRANS_STATE_ENABLE, 50)) > + drm_err(&dev_priv->drm, "Failed to disable PCH transcoder\n"); > + > + /* Workaround: clear timing override bit. */ > + val = intel_de_read(dev_priv, TRANS_CHICKEN2(PIPE_A)); > + val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; > + intel_de_write(dev_priv, TRANS_CHICKEN2(PIPE_A), val); > +} > + > +void lpt_pch_enable(const struct intel_crtc_state *crtc_state) > +{ > + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); > + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); > + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; > + > + assert_pch_transcoder_disabled(dev_priv, PIPE_A); > + > + lpt_program_iclkip(crtc_state); > + > + /* Set transcoder timing. */ > + ilk_pch_transcoder_set_timings(crtc_state, PIPE_A); > + > + lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); > +} > diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.h b/drivers/gpu/drm/i915/display/intel_pch_display.h > new file mode 100644 > index 000000000000..6eba1fd667ea > --- /dev/null > +++ b/drivers/gpu/drm/i915/display/intel_pch_display.h > @@ -0,0 +1,22 @@ > +/* SPDX-License-Identifier: MIT */ > +/* > + * Copyright © 2021 Intel Corporation > + */ > + > +#ifndef _INTEL_PCH_DISPLAY_H_ > +#define _INTEL_PCH_DISPLAY_H_ > + > +enum pipe; > +struct drm_i915_private; > +struct intel_atomic_state; > +struct intel_crtc_state; > + > +void ilk_disable_pch_transcoder(struct drm_i915_private *dev_priv, > + enum pipe pipe); > +void ilk_pch_enable(const struct intel_atomic_state *state, > + const struct intel_crtc_state *crtc_state); > + > +void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv); > +void lpt_pch_enable(const struct intel_crtc_state *crtc_state); > + > +#endif > -- > 2.32.0 >