diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_tv.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_tv.c | 332 |
1 files changed, 170 insertions, 162 deletions
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 62bb048c135..67c6c9a2eb1 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -823,16 +823,14 @@ static const struct tv_mode tv_modes[] = { }, }; -static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder) +static struct intel_tv *enc_to_tv(struct intel_encoder *encoder) { - return container_of(encoder, struct intel_tv, base.base); + return container_of(encoder, struct intel_tv, base); } static struct intel_tv *intel_attached_tv(struct drm_connector *connector) { - return container_of(intel_attached_encoder(connector), - struct intel_tv, - base); + return enc_to_tv(intel_attached_encoder(connector)); } static bool @@ -904,75 +902,46 @@ intel_tv_mode_valid(struct drm_connector *connector, } +static void +intel_tv_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock; +} + static bool -intel_tv_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +intel_tv_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) { - struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + struct intel_tv *intel_tv = enc_to_tv(encoder); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); if (!tv_mode) return false; - if (intel_encoder_check_is_cloned(&intel_tv->base)) - return false; + pipe_config->adjusted_mode.crtc_clock = tv_mode->clock; + DRM_DEBUG_KMS("forcing bpc to 8 for TV\n"); + pipe_config->pipe_bpp = 8*3; + + /* TV has it's own notion of sync and other mode flags, so clear them. */ + pipe_config->adjusted_mode.flags = 0; + + /* + * FIXME: We don't check whether the input mode is actually what we want + * or whether userspace is doing something stupid. + */ - adjusted_mode->clock = tv_mode->clock; return true; } static void -intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +set_tv_mode_timings(struct drm_i915_private *dev_priv, + const struct tv_mode *tv_mode, + bool burst_ena) { - struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = encoder->crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_tv *intel_tv = enc_to_intel_tv(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); - u32 tv_ctl; u32 hctl1, hctl2, hctl3; u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; - u32 scctl1, scctl2, scctl3; - int i, j; - const struct video_levels *video_levels; - const struct color_conversion *color_conversion; - bool burst_ena; - int pipe = intel_crtc->pipe; - - if (!tv_mode) - return; /* can't happen (mode_prepare prevents this) */ - - tv_ctl = I915_READ(TV_CTL); - tv_ctl &= TV_CTL_SAVE; - switch (intel_tv->type) { - default: - case DRM_MODE_CONNECTOR_Unknown: - case DRM_MODE_CONNECTOR_Composite: - tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; - video_levels = tv_mode->composite_levels; - color_conversion = tv_mode->composite_color; - burst_ena = tv_mode->burst_ena; - break; - case DRM_MODE_CONNECTOR_Component: - tv_ctl |= TV_ENC_OUTPUT_COMPONENT; - video_levels = &component_levels; - if (tv_mode->burst_ena) - color_conversion = &sdtv_csc_yprpb; - else - color_conversion = &hdtv_csc_yprpb; - burst_ena = false; - break; - case DRM_MODE_CONNECTOR_SVIDEO: - tv_ctl |= TV_ENC_OUTPUT_SVIDEO; - video_levels = tv_mode->svideo_levels; - color_conversion = tv_mode->svideo_color; - burst_ena = tv_mode->burst_ena; - break; - } hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | (tv_mode->htotal << TV_HTOTAL_SHIFT); @@ -1012,6 +981,86 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) | (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT); + I915_WRITE(TV_H_CTL_1, hctl1); + I915_WRITE(TV_H_CTL_2, hctl2); + I915_WRITE(TV_H_CTL_3, hctl3); + I915_WRITE(TV_V_CTL_1, vctl1); + I915_WRITE(TV_V_CTL_2, vctl2); + I915_WRITE(TV_V_CTL_3, vctl3); + I915_WRITE(TV_V_CTL_4, vctl4); + I915_WRITE(TV_V_CTL_5, vctl5); + I915_WRITE(TV_V_CTL_6, vctl6); + I915_WRITE(TV_V_CTL_7, vctl7); +} + +static void set_color_conversion(struct drm_i915_private *dev_priv, + const struct color_conversion *color_conversion) +{ + if (!color_conversion) + return; + + I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | + color_conversion->gy); + I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) | + color_conversion->ay); + I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | + color_conversion->gu); + I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | + color_conversion->au); + I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | + color_conversion->gv); + I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | + color_conversion->av); +} + +static void intel_tv_pre_enable(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct intel_tv *intel_tv = enc_to_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); + u32 tv_ctl; + u32 scctl1, scctl2, scctl3; + int i, j; + const struct video_levels *video_levels; + const struct color_conversion *color_conversion; + bool burst_ena; + int xpos = 0x0, ypos = 0x0; + unsigned int xsize, ysize; + + if (!tv_mode) + return; /* can't happen (mode_prepare prevents this) */ + + tv_ctl = I915_READ(TV_CTL); + tv_ctl &= TV_CTL_SAVE; + + switch (intel_tv->type) { + default: + case DRM_MODE_CONNECTOR_Unknown: + case DRM_MODE_CONNECTOR_Composite: + tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; + video_levels = tv_mode->composite_levels; + color_conversion = tv_mode->composite_color; + burst_ena = tv_mode->burst_ena; + break; + case DRM_MODE_CONNECTOR_Component: + tv_ctl |= TV_ENC_OUTPUT_COMPONENT; + video_levels = &component_levels; + if (tv_mode->burst_ena) + color_conversion = &sdtv_csc_yprpb; + else + color_conversion = &hdtv_csc_yprpb; + burst_ena = false; + break; + case DRM_MODE_CONNECTOR_SVIDEO: + tv_ctl |= TV_ENC_OUTPUT_SVIDEO; + video_levels = tv_mode->svideo_levels; + color_conversion = tv_mode->svideo_color; + burst_ena = tv_mode->burst_ena; + break; + } + if (intel_crtc->pipe == 1) tv_ctl |= TV_ENC_PIPEB_SELECT; tv_ctl |= tv_mode->oversample; @@ -1042,37 +1091,16 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT; /* Enable two fixes for the chips that need them. */ - if (dev->pci_device < 0x2772) + if (IS_I915GM(dev)) tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX; - I915_WRITE(TV_H_CTL_1, hctl1); - I915_WRITE(TV_H_CTL_2, hctl2); - I915_WRITE(TV_H_CTL_3, hctl3); - I915_WRITE(TV_V_CTL_1, vctl1); - I915_WRITE(TV_V_CTL_2, vctl2); - I915_WRITE(TV_V_CTL_3, vctl3); - I915_WRITE(TV_V_CTL_4, vctl4); - I915_WRITE(TV_V_CTL_5, vctl5); - I915_WRITE(TV_V_CTL_6, vctl6); - I915_WRITE(TV_V_CTL_7, vctl7); + set_tv_mode_timings(dev_priv, tv_mode, burst_ena); + I915_WRITE(TV_SC_CTL_1, scctl1); I915_WRITE(TV_SC_CTL_2, scctl2); I915_WRITE(TV_SC_CTL_3, scctl3); - if (color_conversion) { - I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | - color_conversion->gy); - I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) | - color_conversion->ay); - I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | - color_conversion->gu); - I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | - color_conversion->au); - I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | - color_conversion->gv); - I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | - color_conversion->av); - } + set_color_conversion(dev_priv, color_conversion); if (INTEL_INFO(dev)->gen >= 4) I915_WRITE(TV_CLR_KNOBS, 0x00404000); @@ -1083,49 +1111,25 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, I915_WRITE(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); - { - int pipeconf_reg = PIPECONF(pipe); - int dspcntr_reg = DSPCNTR(intel_crtc->plane); - int pipeconf = I915_READ(pipeconf_reg); - int dspcntr = I915_READ(dspcntr_reg); - int dspbase_reg = DSPADDR(intel_crtc->plane); - int xpos = 0x0, ypos = 0x0; - unsigned int xsize, ysize; - /* Pipe must be off here */ - I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); - - /* Wait for vblank for the disable to take effect */ - if (IS_GEN2(dev)) - intel_wait_for_vblank(dev, intel_crtc->pipe); - - I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE); - /* Wait for vblank for the disable to take effect. */ - intel_wait_for_pipe_off(dev, intel_crtc->pipe); - - /* Filter ctl must be set before TV_WIN_SIZE */ - I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); - xsize = tv_mode->hblank_start - tv_mode->hblank_end; - if (tv_mode->progressive) - ysize = tv_mode->nbr_end + 1; - else - ysize = 2*tv_mode->nbr_end + 1; - - xpos += intel_tv->margin[TV_MARGIN_LEFT]; - ypos += intel_tv->margin[TV_MARGIN_TOP]; - xsize -= (intel_tv->margin[TV_MARGIN_LEFT] + - intel_tv->margin[TV_MARGIN_RIGHT]); - ysize -= (intel_tv->margin[TV_MARGIN_TOP] + - intel_tv->margin[TV_MARGIN_BOTTOM]); - I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); - I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); - - I915_WRITE(pipeconf_reg, pipeconf); - I915_WRITE(dspcntr_reg, dspcntr); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); - } + + assert_pipe_disabled(dev_priv, intel_crtc->pipe); + + /* Filter ctl must be set before TV_WIN_SIZE */ + I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); + xsize = tv_mode->hblank_start - tv_mode->hblank_end; + if (tv_mode->progressive) + ysize = tv_mode->nbr_end + 1; + else + ysize = 2*tv_mode->nbr_end + 1; + + xpos += intel_tv->margin[TV_MARGIN_LEFT]; + ypos += intel_tv->margin[TV_MARGIN_TOP]; + xsize -= (intel_tv->margin[TV_MARGIN_LEFT] + + intel_tv->margin[TV_MARGIN_RIGHT]); + ysize -= (intel_tv->margin[TV_MARGIN_TOP] + + intel_tv->margin[TV_MARGIN_BOTTOM]); + I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); + I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); j = 0; for (i = 0; i < 60; i++) @@ -1183,8 +1187,8 @@ intel_tv_detect_type(struct intel_tv *intel_tv, if (connector->polled & DRM_CONNECTOR_POLL_HPD) { spin_lock_irqsave(&dev_priv->irq_lock, irqflags); i915_disable_pipestat(dev_priv, 0, - PIPE_HOTPLUG_INTERRUPT_ENABLE | - PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); + PIPE_HOTPLUG_INTERRUPT_STATUS | + PIPE_HOTPLUG_TV_INTERRUPT_STATUS); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } @@ -1260,8 +1264,8 @@ intel_tv_detect_type(struct intel_tv *intel_tv, if (connector->polled & DRM_CONNECTOR_POLL_HPD) { spin_lock_irqsave(&dev_priv->irq_lock, irqflags); i915_enable_pipestat(dev_priv, 0, - PIPE_HOTPLUG_INTERRUPT_ENABLE | - PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); + PIPE_HOTPLUG_INTERRUPT_STATUS | + PIPE_HOTPLUG_TV_INTERRUPT_STATUS); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } @@ -1292,7 +1296,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector) } intel_tv->tv_format = tv_mode->name; - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, connector->dev->mode_config.tv_mode_property, i); } @@ -1309,14 +1313,19 @@ intel_tv_detect(struct drm_connector *connector, bool force) struct intel_tv *intel_tv = intel_attached_tv(connector); int type; + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n", + connector->base.id, connector->name, + force); + mode = reported_modes[0]; if (force) { struct intel_load_detect_pipe tmp; + struct drm_modeset_acquire_ctx ctx; - if (intel_get_load_detect_pipe(connector, &mode, &tmp)) { + if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) { type = intel_tv_detect_type(intel_tv, connector); - intel_release_load_detect_pipe(connector, &tmp); + intel_release_load_detect_pipe(connector, &tmp, &ctx); } else return connector_status_unknown; } else @@ -1430,7 +1439,6 @@ intel_tv_get_modes(struct drm_connector *connector) static void intel_tv_destroy(struct drm_connector *connector) { - drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(connector); } @@ -1446,7 +1454,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop int ret = 0; bool changed = false; - ret = drm_connector_property_set_value(connector, property, val); + ret = drm_object_property_set_value(&connector->base, property, val); if (ret < 0) goto out; @@ -1482,18 +1490,11 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop } if (changed && crtc) - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); + intel_crtc_restore_mode(crtc); out: return ret; } -static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { - .mode_fixup = intel_tv_mode_fixup, - .mode_set = intel_tv_mode_set, - .disable = intel_encoder_noop, -}; - static const struct drm_connector_funcs intel_tv_connector_funcs = { .dpms = intel_connector_dpms, .detect = intel_tv_detect, @@ -1522,25 +1523,30 @@ static const struct drm_encoder_funcs intel_tv_enc_funcs = { static int tv_is_present_in_vbt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct child_device_config *p_child; + union child_device_config *p_child; int i, ret; - if (!dev_priv->child_dev_num) + if (!dev_priv->vbt.child_dev_num) return 1; ret = 0; - for (i = 0; i < dev_priv->child_dev_num; i++) { - p_child = dev_priv->child_dev + i; + for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { + p_child = dev_priv->vbt.child_dev + i; /* * If the device type is not TV, continue. */ - if (p_child->device_type != DEVICE_TYPE_INT_TV && - p_child->device_type != DEVICE_TYPE_TV) + switch (p_child->old.device_type) { + case DEVICE_TYPE_INT_TV: + case DEVICE_TYPE_TV: + case DEVICE_TYPE_TV_SVIDEO_COMPOSITE: + break; + default: continue; + } /* Only when the addin_offset is non-zero, it is regarded * as present. */ - if (p_child->addin_offset) { + if (p_child->old.addin_offset) { ret = 1; break; } @@ -1568,7 +1574,7 @@ intel_tv_init(struct drm_device *dev) return; } /* Even if we have an encoder we may not have a connector */ - if (!dev_priv->int_tv_support) + if (!dev_priv->vbt.int_tv_support) return; /* @@ -1594,12 +1600,12 @@ intel_tv_init(struct drm_device *dev) (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) return; - intel_tv = kzalloc(sizeof(struct intel_tv), GFP_KERNEL); + intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL); if (!intel_tv) { return; } - intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); + intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL); if (!intel_connector) { kfree(intel_tv); return; @@ -1617,7 +1623,7 @@ intel_tv_init(struct drm_device *dev) * * More recent chipsets favour HDMI rather than integrated S-Video. */ - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); @@ -1625,17 +1631,20 @@ intel_tv_init(struct drm_device *dev) drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC); + intel_encoder->compute_config = intel_tv_compute_config; + intel_encoder->get_config = intel_tv_get_config; + intel_encoder->pre_enable = intel_tv_pre_enable; intel_encoder->enable = intel_enable_tv; intel_encoder->disable = intel_disable_tv; intel_encoder->get_hw_state = intel_tv_get_hw_state; intel_connector->get_hw_state = intel_connector_get_hw_state; + intel_connector->unregister = intel_connector_unregister; intel_connector_attach_encoder(intel_connector, intel_encoder); intel_encoder->type = INTEL_OUTPUT_TVOUT; intel_encoder->crtc_mask = (1 << 0) | (1 << 1); - intel_encoder->cloneable = false; + intel_encoder->cloneable = 0; intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1)); - intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT); intel_tv->type = DRM_MODE_CONNECTOR_Unknown; /* BIOS margin values */ @@ -1646,7 +1655,6 @@ intel_tv_init(struct drm_device *dev) intel_tv->tv_format = tv_modes[initial_mode].name; - drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs); drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); connector->interlace_allowed = false; connector->doublescan_allowed = false; @@ -1658,18 +1666,18 @@ intel_tv_init(struct drm_device *dev) ARRAY_SIZE(tv_modes), tv_format_names); - drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, + drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property, initial_mode); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_left_margin_property, intel_tv->margin[TV_MARGIN_LEFT]); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_top_margin_property, intel_tv->margin[TV_MARGIN_TOP]); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_right_margin_property, intel_tv->margin[TV_MARGIN_RIGHT]); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_bottom_margin_property, intel_tv->margin[TV_MARGIN_BOTTOM]); drm_sysfs_connector_add(connector); |
