Commit b024ab9b authored by Jani Nikula's avatar Jani Nikula

drm/i915/bios: iterate over child devices to initialize ddi_port_info

Iterate over child devices instead of ports in parse_ddi_ports() to
initialize ddi_port_info. We'll eventually need to decide some stuff
based on the child device order, which may be different from the port
order.

As a bonus, this allows better abstractions for e.g. dvo port mapping.

There's a subtle change in the DDC pin and AUX channel sanitization as
we change the order. Otherwise, this should not change behaviour.
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190322121008.4456-1-jani.nikula@intel.com
parent 32c13bcd
...@@ -957,6 +957,7 @@ struct ddi_vbt_port_info { ...@@ -957,6 +957,7 @@ struct ddi_vbt_port_info {
#define HDMI_LEVEL_SHIFT_UNKNOWN 0xff #define HDMI_LEVEL_SHIFT_UNKNOWN 0xff
u8 hdmi_level_shift; u8 hdmi_level_shift;
u8 present:1;
u8 supports_dvi:1; u8 supports_dvi:1;
u8 supports_hdmi:1; u8 supports_hdmi:1;
u8 supports_dp:1; u8 supports_dp:1;
......
...@@ -1247,10 +1247,11 @@ static void sanitize_ddc_pin(struct drm_i915_private *dev_priv, ...@@ -1247,10 +1247,11 @@ static void sanitize_ddc_pin(struct drm_i915_private *dev_priv,
if (!info->alternate_ddc_pin) if (!info->alternate_ddc_pin)
return; return;
for_each_port_masked(p, (1 << port) - 1) { for (p = PORT_A; p < I915_MAX_PORTS; p++) {
struct ddi_vbt_port_info *i = &dev_priv->vbt.ddi_port_info[p]; struct ddi_vbt_port_info *i = &dev_priv->vbt.ddi_port_info[p];
if (info->alternate_ddc_pin != i->alternate_ddc_pin) if (p == port || !i->present ||
info->alternate_ddc_pin != i->alternate_ddc_pin)
continue; continue;
DRM_DEBUG_KMS("port %c trying to use the same DDC pin (0x%x) as port %c, " DRM_DEBUG_KMS("port %c trying to use the same DDC pin (0x%x) as port %c, "
...@@ -1264,8 +1265,8 @@ static void sanitize_ddc_pin(struct drm_i915_private *dev_priv, ...@@ -1264,8 +1265,8 @@ static void sanitize_ddc_pin(struct drm_i915_private *dev_priv,
* port. Otherwise they share the same ddc bin and * port. Otherwise they share the same ddc bin and
* system couldn't communicate with them separately. * system couldn't communicate with them separately.
* *
* Due to parsing the ports in alphabetical order, * Due to parsing the ports in child device order,
* a higher port will always clobber a lower one. * a later device will always clobber an earlier one.
*/ */
i->supports_dvi = false; i->supports_dvi = false;
i->supports_hdmi = false; i->supports_hdmi = false;
...@@ -1283,10 +1284,11 @@ static void sanitize_aux_ch(struct drm_i915_private *dev_priv, ...@@ -1283,10 +1284,11 @@ static void sanitize_aux_ch(struct drm_i915_private *dev_priv,
if (!info->alternate_aux_channel) if (!info->alternate_aux_channel)
return; return;
for_each_port_masked(p, (1 << port) - 1) { for (p = PORT_A; p < I915_MAX_PORTS; p++) {
struct ddi_vbt_port_info *i = &dev_priv->vbt.ddi_port_info[p]; struct ddi_vbt_port_info *i = &dev_priv->vbt.ddi_port_info[p];
if (info->alternate_aux_channel != i->alternate_aux_channel) if (p == port || !i->present ||
info->alternate_aux_channel != i->alternate_aux_channel)
continue; continue;
DRM_DEBUG_KMS("port %c trying to use the same AUX CH (0x%x) as port %c, " DRM_DEBUG_KMS("port %c trying to use the same AUX CH (0x%x) as port %c, "
...@@ -1300,8 +1302,8 @@ static void sanitize_aux_ch(struct drm_i915_private *dev_priv, ...@@ -1300,8 +1302,8 @@ static void sanitize_aux_ch(struct drm_i915_private *dev_priv,
* port. Otherwise they share the same aux channel * port. Otherwise they share the same aux channel
* and system couldn't communicate with them separately. * and system couldn't communicate with them separately.
* *
* Due to parsing the ports in alphabetical order, * Due to parsing the ports in child device order,
* a higher port will always clobber a lower one. * a later device will always clobber an earlier one.
*/ */
i->supports_dp = false; i->supports_dp = false;
i->alternate_aux_channel = 0; i->alternate_aux_channel = 0;
...@@ -1349,48 +1351,57 @@ static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin) ...@@ -1349,48 +1351,57 @@ static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin)
return 0; return 0;
} }
static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, static enum port dvo_port_to_port(u8 dvo_port)
u8 bdb_version)
{ {
struct child_device_config *it, *child = NULL; /*
struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; * Each DDI port can have more than one value on the "DVO Port" field,
int i, j;
bool is_dvi, is_hdmi, is_dp, is_edp, is_crt;
/* Each DDI port can have more than one value on the "DVO Port" field,
* so look for all the possible values for each port. * so look for all the possible values for each port.
*/ */
int dvo_ports[][3] = { static const int dvo_ports[][3] = {
{DVO_PORT_HDMIA, DVO_PORT_DPA, -1}, [PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1},
{DVO_PORT_HDMIB, DVO_PORT_DPB, -1}, [PORT_B] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1},
{DVO_PORT_HDMIC, DVO_PORT_DPC, -1}, [PORT_C] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1},
{DVO_PORT_HDMID, DVO_PORT_DPD, -1}, [PORT_D] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1},
{DVO_PORT_CRT, DVO_PORT_HDMIE, DVO_PORT_DPE}, [PORT_E] = { DVO_PORT_CRT, DVO_PORT_HDMIE, DVO_PORT_DPE},
{DVO_PORT_HDMIF, DVO_PORT_DPF, -1}, [PORT_F] = { DVO_PORT_HDMIF, DVO_PORT_DPF, -1},
}; };
enum port port;
int i;
/* for (port = PORT_A; port < ARRAY_SIZE(dvo_ports); port++) {
* Find the first child device to reference the port, report if more for (i = 0; i < ARRAY_SIZE(dvo_ports[port]); i++) {
* than one found. if (dvo_ports[port][i] == -1)
*/
for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
it = dev_priv->vbt.child_dev + i;
for (j = 0; j < 3; j++) {
if (dvo_ports[port][j] == -1)
break; break;
if (it->dvo_port == dvo_ports[port][j]) { if (dvo_port == dvo_ports[port][i])
if (child) { return port;
DRM_DEBUG_KMS("More than one child device for port %c in VBT, using the first.\n",
port_name(port));
} else {
child = it;
}
} }
} }
}
if (!child) return PORT_NONE;
}
static void parse_ddi_port(struct drm_i915_private *dev_priv,
const struct child_device_config *child,
u8 bdb_version)
{
struct ddi_vbt_port_info *info;
bool is_dvi, is_hdmi, is_dp, is_edp, is_crt;
enum port port;
port = dvo_port_to_port(child->dvo_port);
if (port == PORT_NONE)
return;
info = &dev_priv->vbt.ddi_port_info[port];
if (info->present) {
DRM_DEBUG_KMS("More than one child device for port %c in VBT, using the first.\n",
port_name(port));
return; return;
}
info->present = true;
is_dvi = child->device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; is_dvi = child->device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING;
is_dp = child->device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; is_dp = child->device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT;
...@@ -1523,19 +1534,20 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, ...@@ -1523,19 +1534,20 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
static void parse_ddi_ports(struct drm_i915_private *dev_priv, u8 bdb_version) static void parse_ddi_ports(struct drm_i915_private *dev_priv, u8 bdb_version)
{ {
enum port port; const struct child_device_config *child;
int i;
if (!HAS_DDI(dev_priv) && !IS_CHERRYVIEW(dev_priv)) if (!HAS_DDI(dev_priv) && !IS_CHERRYVIEW(dev_priv))
return; return;
if (!dev_priv->vbt.child_dev_num)
return;
if (bdb_version < 155) if (bdb_version < 155)
return; return;
for (port = PORT_A; port < I915_MAX_PORTS; port++) for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
parse_ddi_port(dev_priv, port, bdb_version); child = dev_priv->vbt.child_dev + i;
parse_ddi_port(dev_priv, child, bdb_version);
}
} }
static void static void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment