return ret;
}
- intel_update_pipe_size(intel_crtc);
-
dev_priv->display.update_primary_plane(crtc, fb, x, y);
if (intel_crtc->active)
}
}
+static void skylake_pfit_enable(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe = crtc->pipe;
+
+ if (crtc->config.pch_pfit.enabled) {
+ I915_WRITE(PS_CTL(pipe), PS_ENABLE);
+ I915_WRITE(PS_WIN_POS(pipe), crtc->config.pch_pfit.pos);
+ I915_WRITE(PS_WIN_SZ(pipe), crtc->config.pch_pfit.size);
+ }
+}
+
static void ironlake_pfit_enable(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
intel_ddi_enable_pipe_clock(intel_crtc);
- ironlake_pfit_enable(intel_crtc);
+ if (IS_SKYLAKE(dev))
+ skylake_pfit_enable(intel_crtc);
+ else
+ ironlake_pfit_enable(intel_crtc);
/*
* On ILK+ LUT must be loaded before the pipe is running but with
intel_crtc_enable_planes(crtc);
}
+static void skylake_pfit_disable(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe = crtc->pipe;
+
+ /* To avoid upsetting the power well on haswell only disable the pfit if
+ * it's in use. The hw state code will make sure we get this right. */
+ if (crtc->config.pch_pfit.enabled) {
+ I915_WRITE(PS_CTL(pipe), 0);
+ I915_WRITE(PS_WIN_POS(pipe), 0);
+ I915_WRITE(PS_WIN_SZ(pipe), 0);
+ }
+}
+
static void ironlake_pfit_disable(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
- ironlake_pfit_disable(intel_crtc);
+ if (IS_SKYLAKE(dev))
+ skylake_pfit_disable(intel_crtc);
+ else
+ ironlake_pfit_disable(intel_crtc);
intel_ddi_disable_pipe_clock(intel_crtc);
* BSpec erroneously claims we should aim for 4MHz, but
* in fact 1MHz is the correct frequency.
*/
- I915_WRITE(GMBUSFREQ_VLV, dev_priv->vlv_cdclk_freq);
+ I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->vlv_cdclk_freq, 1000));
}
/* Adjust CDclk dividers to allow high res or save power if possible */
&pipe_config->fdi_m_n, NULL);
}
+static void skylake_get_pfit_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t tmp;
+
+ tmp = I915_READ(PS_CTL(crtc->pipe));
+
+ if (tmp & PS_ENABLE) {
+ pipe_config->pch_pfit.enabled = true;
+ pipe_config->pch_pfit.pos = I915_READ(PS_WIN_POS(crtc->pipe));
+ pipe_config->pch_pfit.size = I915_READ(PS_WIN_SZ(crtc->pipe));
+ }
+}
+
static void ironlake_get_pfit_config(struct intel_crtc *crtc,
struct intel_crtc_config *pipe_config)
{
return 0;
}
+static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
+ enum port port,
+ struct intel_crtc_config *pipe_config)
+{
+ u32 temp;
+
+ temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
+ pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
+
+ switch (pipe_config->ddi_pll_sel) {
+ case SKL_DPLL1:
+ pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
+ break;
+ case SKL_DPLL2:
+ pipe_config->shared_dpll = DPLL_ID_SKL_DPLL2;
+ break;
+ case SKL_DPLL3:
+ pipe_config->shared_dpll = DPLL_ID_SKL_DPLL3;
+ break;
+ }
+}
+
static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
enum port port,
struct intel_crtc_config *pipe_config)
port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT;
- haswell_get_ddi_pll(dev_priv, port, pipe_config);
+ if (IS_SKYLAKE(dev))
+ skylake_get_ddi_pll(dev_priv, port, pipe_config);
+ else
+ haswell_get_ddi_pll(dev_priv, port, pipe_config);
if (pipe_config->shared_dpll >= 0) {
pll = &dev_priv->shared_dplls[pipe_config->shared_dpll];
intel_get_pipe_timings(crtc, pipe_config);
pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
- if (intel_display_power_is_enabled(dev_priv, pfit_domain))
- ironlake_get_pfit_config(crtc, pipe_config);
+ if (intel_display_power_is_enabled(dev_priv, pfit_domain)) {
+ if (IS_SKYLAKE(dev))
+ skylake_get_pfit_config(crtc, pipe_config);
+ else
+ ironlake_get_pfit_config(crtc, pipe_config);
+ }
if (IS_HASWELL(dev))
pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
return 0;
}
+static int intel_gen9_queue_flip(struct drm_device *dev,
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_i915_gem_object *obj,
+ struct intel_engine_cs *ring,
+ uint32_t flags)
+{
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ uint32_t plane = 0, stride;
+ int ret;
+
+ switch(intel_crtc->pipe) {
+ case PIPE_A:
+ plane = MI_DISPLAY_FLIP_SKL_PLANE_1_A;
+ break;
+ case PIPE_B:
+ plane = MI_DISPLAY_FLIP_SKL_PLANE_1_B;
+ break;
+ case PIPE_C:
+ plane = MI_DISPLAY_FLIP_SKL_PLANE_1_C;
+ break;
+ default:
+ WARN_ONCE(1, "unknown plane in flip command\n");
+ return -ENODEV;
+ }
+
+ switch (obj->tiling_mode) {
+ case I915_TILING_NONE:
+ stride = fb->pitches[0] >> 6;
+ break;
+ case I915_TILING_X:
+ stride = fb->pitches[0] >> 9;
+ break;
+ default:
+ WARN_ONCE(1, "unknown tiling in flip command\n");
+ return -ENODEV;
+ }
+
+ ret = intel_ring_begin(ring, 10);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+ intel_ring_emit(ring, DERRMR);
+ intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
+ DERRMR_PIPEB_PRI_FLIP_DONE |
+ DERRMR_PIPEC_PRI_FLIP_DONE));
+ intel_ring_emit(ring, MI_STORE_REGISTER_MEM_GEN8(1) |
+ MI_SRM_LRM_GLOBAL_GTT);
+ intel_ring_emit(ring, DERRMR);
+ intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
+ intel_ring_emit(ring, 0);
+
+ intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane);
+ intel_ring_emit(ring, stride << 6 | obj->tiling_mode);
+ intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
+
+ intel_mark_page_flip_active(intel_crtc);
+ __intel_ring_advance(ring);
+
+ return 0;
+}
+
static int intel_default_queue_flip(struct drm_device *dev,
struct drm_crtc *crtc,
struct drm_framebuffer *fb,
if ((INTEL_INFO(dev)->gen < 8 && !IS_HASWELL(dev)) ||
IS_VALLEYVIEW(dev))
PIPE_CONF_CHECK_I(limited_color_range);
+ PIPE_CONF_CHECK_I(has_infoframe);
PIPE_CONF_CHECK_I(has_audio);
PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
+ PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5)
PIPE_CONF_CHECK_I(pipe_bpp);
crtc->scanline_offset = 1;
}
+static struct intel_crtc_config *
+intel_modeset_compute_config(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_framebuffer *fb,
+ unsigned *modeset_pipes,
+ unsigned *prepare_pipes,
+ unsigned *disable_pipes)
+{
+ struct intel_crtc_config *pipe_config = NULL;
+
+ intel_modeset_affected_pipes(crtc, modeset_pipes,
+ prepare_pipes, disable_pipes);
+
+ if ((*modeset_pipes) == 0)
+ goto out;
+
+ /*
+ * Note this needs changes when we start tracking multiple modes
+ * and crtcs. At that point we'll need to compute the whole config
+ * (i.e. one pipe_config for each crtc) rather than just the one
+ * for this crtc.
+ */
+ pipe_config = intel_modeset_pipe_config(crtc, fb, mode);
+ if (IS_ERR(pipe_config)) {
+ goto out;
+ }
+ intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
+ "[modeset]");
+ to_intel_crtc(crtc)->new_config = pipe_config;
+
+out:
+ return pipe_config;
+}
+
static int __intel_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode,
- int x, int y, struct drm_framebuffer *fb)
+ int x, int y, struct drm_framebuffer *fb,
+ struct intel_crtc_config *pipe_config,
+ unsigned modeset_pipes,
+ unsigned prepare_pipes,
+ unsigned disable_pipes)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_display_mode *saved_mode;
- struct intel_crtc_config *pipe_config = NULL;
struct intel_crtc *intel_crtc;
- unsigned disable_pipes, prepare_pipes, modeset_pipes;
int ret = 0;
saved_mode = kmalloc(sizeof(*saved_mode), GFP_KERNEL);
if (!saved_mode)
return -ENOMEM;
- intel_modeset_affected_pipes(crtc, &modeset_pipes,
- &prepare_pipes, &disable_pipes);
-
*saved_mode = crtc->mode;
- /* Hack: Because we don't (yet) support global modeset on multiple
- * crtcs, we don't keep track of the new mode for more than one crtc.
- * Hence simply check whether any bit is set in modeset_pipes in all the
- * pieces of code that are not yet converted to deal with mutliple crtcs
- * changing their mode at the same time. */
- if (modeset_pipes) {
- pipe_config = intel_modeset_pipe_config(crtc, fb, mode);
- if (IS_ERR(pipe_config)) {
- ret = PTR_ERR(pipe_config);
- pipe_config = NULL;
-
- goto out;
- }
- intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
- "[modeset]");
- to_intel_crtc(crtc)->new_config = pipe_config;
- }
-
/*
* See if the config requires any additional preparation, e.g.
* to adjust global state with pipes off. We need to do this
/* crtc->mode is already used by the ->mode_set callbacks, hence we need
* to set it here already despite that we pass it down the callchain.
+ *
+ * Note we'll need to fix this up when we start tracking multiple
+ * pipes; here we assume a single modeset_pipe and only track the
+ * single crtc and mode.
*/
if (modeset_pipes) {
crtc->mode = *mode;
if (ret && crtc->enabled)
crtc->mode = *saved_mode;
-out:
kfree(pipe_config);
kfree(saved_mode);
return ret;
}
-static int intel_set_mode(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- int x, int y, struct drm_framebuffer *fb)
+static int intel_set_mode_pipes(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ int x, int y, struct drm_framebuffer *fb,
+ struct intel_crtc_config *pipe_config,
+ unsigned modeset_pipes,
+ unsigned prepare_pipes,
+ unsigned disable_pipes)
{
int ret;
- ret = __intel_set_mode(crtc, mode, x, y, fb);
+ ret = __intel_set_mode(crtc, mode, x, y, fb, pipe_config, modeset_pipes,
+ prepare_pipes, disable_pipes);
if (ret == 0)
intel_modeset_check_state(crtc->dev);
return ret;
}
+static int intel_set_mode(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ int x, int y, struct drm_framebuffer *fb)
+{
+ struct intel_crtc_config *pipe_config;
+ unsigned modeset_pipes, prepare_pipes, disable_pipes;
+
+ pipe_config = intel_modeset_compute_config(crtc, mode, fb,
+ &modeset_pipes,
+ &prepare_pipes,
+ &disable_pipes);
+
+ if (IS_ERR(pipe_config))
+ return PTR_ERR(pipe_config);
+
+ return intel_set_mode_pipes(crtc, mode, x, y, fb, pipe_config,
+ modeset_pipes, prepare_pipes,
+ disable_pipes);
+}
+
void intel_crtc_restore_mode(struct drm_crtc *crtc)
{
intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb);
struct drm_device *dev;
struct drm_mode_set save_set;
struct intel_set_config *config;
+ struct intel_crtc_config *pipe_config;
+ unsigned modeset_pipes, prepare_pipes, disable_pipes;
int ret;
BUG_ON(!set);
if (ret)
goto fail;
+ pipe_config = intel_modeset_compute_config(set->crtc, set->mode,
+ set->fb,
+ &modeset_pipes,
+ &prepare_pipes,
+ &disable_pipes);
+ if (IS_ERR(pipe_config)) {
+ ret = PTR_ERR(pipe_config);
+ goto fail;
+ } else if (pipe_config) {
+ if (to_intel_crtc(set->crtc)->new_config->has_audio !=
+ to_intel_crtc(set->crtc)->config.has_audio)
+ config->mode_changed = true;
+
+ /* Force mode sets for any infoframe stuff */
+ if (to_intel_crtc(set->crtc)->new_config->has_infoframe ||
+ to_intel_crtc(set->crtc)->config.has_infoframe)
+ config->mode_changed = true;
+ }
+
+ /* set_mode will free it in the mode_changed case */
+ if (!config->mode_changed)
+ kfree(pipe_config);
+
+ intel_update_pipe_size(to_intel_crtc(set->crtc));
+
if (config->mode_changed) {
- ret = intel_set_mode(set->crtc, set->mode,
- set->x, set->y, set->fb);
+ ret = intel_set_mode_pipes(set->crtc, set->mode,
+ set->x, set->y, set->fb, pipe_config,
+ modeset_pipes, prepare_pipes,
+ disable_pipes);
} else if (config->fb_changed) {
struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
struct drm_rect *src = &state->src;
crtc->primary->fb = fb;
- crtc->x = src->x1;
- crtc->y = src->y1;
+ crtc->x = src->x1 >> 16;
+ crtc->y = src->y1 >> 16;
intel_plane->crtc_x = state->orig_dst.x1;
intel_plane->crtc_y = state->orig_dst.y1;
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
- if (!encoder)
+ if (!encoder || WARN_ON(!encoder->crtc))
return INVALID_PIPE;
return to_intel_crtc(encoder->crtc)->pipe;
if (SUPPORTS_TV(dev))
intel_tv_init(dev);
- intel_edp_psr_init(dev);
+ intel_psr_init(dev);
for_each_intel_encoder(dev, encoder) {
encoder->base.possible_crtcs = encoder->crtc_mask;
case 8: /* FIXME(BDW): Check that the gen8 RCS flip works. */
dev_priv->display.queue_flip = intel_gen7_queue_flip;
break;
+ case 9:
+ dev_priv->display.queue_flip = intel_gen9_queue_flip;
+ break;
}
intel_panel_init_backlight_funcs(dev);
/* Acer C720 Chromebook (Core i3 4005U) */
{ 0x0a16, 0x1025, 0x0a11, quirk_backlight_present },
+ /* Apple Macbook 2,1 (Core 2 T7400) */
+ { 0x27a2, 0x8086, 0x7270, quirk_backlight_present },
+
/* Toshiba CB35 Chromebook (Celeron 2955U) */
{ 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
struct drm_crtc *crtc =
dev_priv->pipe_to_crtc_mapping[pipe];
- __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
- crtc->primary->fb);
+ intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
+ crtc->primary->fb);
}
} else {
intel_modeset_update_staged_output_state(dev);
void intel_modeset_gem_init(struct drm_device *dev)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *c;
struct drm_i915_gem_object *obj;
intel_init_gt_powersave(dev);
mutex_unlock(&dev->struct_mutex);
+ /*
+ * There may be no VBT; and if the BIOS enabled SSC we can
+ * just keep using it to avoid unnecessary flicker. Whereas if the
+ * BIOS isn't using it, don't assume it will work even if the VBT
+ * indicates as much.
+ */
+ if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+ dev_priv->vbt.lvds_use_ssc = !!(I915_READ(PCH_DREF_CONTROL) &
+ DREF_SSC1_ENABLE);
+
intel_modeset_init_hw(dev);
intel_setup_overlay(dev);
}
}
mutex_unlock(&dev->struct_mutex);
+
+ intel_backlight_register(dev);
}
void intel_connector_unregister(struct intel_connector *intel_connector)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector;
+ intel_disable_gt_powersave(dev);
+
+ intel_backlight_unregister(dev);
+
/*
* Interrupts and polling as the first thing to avoid creating havoc.
- * Too much stuff here (turning of rps, connectors, ...) would
+ * Too much stuff here (turning of connectors, ...) would
* experience fancy races otherwise.
*/
intel_irq_uninstall(dev_priv);
intel_disable_fbc(dev);
- intel_disable_gt_powersave(dev);
-
ironlake_teardown_rc6(dev);
mutex_unlock(&dev->struct_mutex);