[Intel-gfx] [PATCH 2/5] drm/i915: use the HDMI DDI buffer translations from VBT
Chris Wilson
chris at chris-wilson.co.uk
Wed Sep 11 23:33:02 CEST 2013
On Wed, Sep 11, 2013 at 06:02:48PM -0300, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni at intel.com>
>
> We currently use the recommended values from BSpec, but the VBT
> specifies the correct value to use for the hardware we have, so use
> it. We also fall back to the recommended value in case we can't find
> the VBT.
>
> In addition, this code also provides some infrastructure to parse more
> information about the DDI ports. There's a lot more information we
> could extract and use in the future.
>
> v2: - Move some code to init_vbt_defaults.
> v3: - Rebase
> - Clarify the "DVO Port" matching code
>
> Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com>
> ---
> drivers/gpu/drm/i915/i915_drv.h | 6 +++
> drivers/gpu/drm/i915/intel_bios.c | 78 +++++++++++++++++++++++++++++++++++++++
> drivers/gpu/drm/i915/intel_bios.h | 13 +++++++
> drivers/gpu/drm/i915/intel_ddi.c | 24 +++++++++++-
> 4 files changed, 119 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index ca8856a..298c671 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1052,6 +1052,10 @@ enum modeset_restore {
> MODESET_SUSPENDED,
> };
>
> +struct ddi_vbt_port_info {
> + uint8_t hdmi_level_shift;
> +};
> +
> struct intel_vbt_data {
> struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
> struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
> @@ -1086,6 +1090,8 @@ struct intel_vbt_data {
>
> int child_dev_num;
> union child_device_config *child_dev;
> +
> + struct ddi_vbt_port_info ddi_port_info[5];
s/5/PORT_E+1/ or better #define NUM_DDI_PORTS PORT_E+1.
> };
>
> enum intel_ddb_partitioning {
> diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
> index 33003b9..d7ff8fc 100644
> --- a/drivers/gpu/drm/i915/intel_bios.c
> +++ b/drivers/gpu/drm/i915/intel_bios.c
> @@ -583,6 +583,72 @@ parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
> dev_priv->vbt.dsi.panel_id = mipi->panel_id;
> }
>
> +static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
> + struct bdb_header *bdb)
> +{
> + union child_device_config *it, *child = NULL;
> + struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port];
> + uint8_t hdmi_level_shift;
> + int i, j;
> + /* Each DDI port can have more than one value on the "DVO Port" field,
> + * so look for all the possible values for each port and abort if more
> + * than one is found. */
> + int dvo_ports[][2] = {
> + {DVO_PORT_HDMIA, DVO_PORT_DPA},
> + {DVO_PORT_HDMIB, DVO_PORT_DPB},
> + {DVO_PORT_HDMIC, DVO_PORT_DPC},
> + {DVO_PORT_HDMID, DVO_PORT_DPD},
> + {DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ },
> + };
> +
I don't see the point of calling this function if bdb->version < 158 ?
> + /* Find the child device to use, abort if more than one found. */
> + for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
> + it = dev_priv->vbt.child_dev + i;
> +
> + for (j = 0; j < 2; j++) {
> + if (dvo_ports[port][j] == -1)
> + break;
> +
> + if (it->common.dvo_port == dvo_ports[port][j]) {
> + if (child) {
> + DRM_ERROR("More than one child device for port %c in VBT.\n",
> + port_name(port));
> + return;
> + }
> + child = it;
> + }
> + }
> + }
> + if (!child)
> + return;
> +
> + if (bdb->version >= 158) {
> + /* The VBT HDMI level shift values match the table we have. */
> + hdmi_level_shift = child->raw[7] & 0xF;
> + if (hdmi_level_shift < 0xC) {
> + DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n",
> + port_name(port),
> + hdmi_level_shift);
> + info->hdmi_level_shift = hdmi_level_shift;
> + }
> + }
> +}
> +
> +static void parse_ddi_ports(struct drm_i915_private *dev_priv,
> + struct bdb_header *bdb)
> +{
> + enum port port;
> +
> + if (!dev_priv->vbt.child_dev_num)
> + return;
> +
> + if (bdb->version < 155)
> + return;
> +
> + for (port = PORT_A; port <= PORT_E; port++)
> + parse_ddi_port(dev_priv, port, bdb);
> +}
> +
> static void
> parse_device_mapping(struct drm_i915_private *dev_priv,
> struct bdb_header *bdb)
> @@ -670,6 +736,16 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
> dev_priv->vbt.lvds_use_ssc = 1;
> dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
> DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq);
> +
> + if (HAS_DDI(dev)) {
Might as well just set the defaults anyway. I only really care if the
recommendations change between generations.
> + enum port port;
> +
> + for (port = PORT_A; port <= PORT_E; port++) {
> + /* Recommended BSpec default: 800mV 0dB. */
> + dev_priv->vbt.ddi_port_info[port].hdmi_level_shift = 6;
> + }
> + }
> +
> }
>
> static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
> @@ -761,6 +837,8 @@ intel_parse_bios(struct drm_device *dev)
> parse_driver_features(dev_priv, bdb);
> parse_edp(dev_priv, bdb);
> parse_mipi(dev_priv, bdb);
> + if (HAS_DDI(dev))
> + parse_ddi_ports(dev_priv, bdb);
Move the check here into parse_ddi_ports() so the calling sequence is
clear.
--
Chris Wilson, Intel Open Source Technology Centre
More information about the Intel-gfx
mailing list