summaryrefslogtreecommitdiff
path: root/linux-core/nv50_kms_wrapper.c
diff options
context:
space:
mode:
authorMaarten Maathuis <madman2003@gmail.com>2008-07-04 17:17:11 +0200
committerMaarten Maathuis <madman2003@gmail.com>2008-07-04 17:19:11 +0200
commitb29578103f57a8d684b4a3a79f220e6cc626605e (patch)
tree166e89f2b744f95451949d5c46a704002510ddf0 /linux-core/nv50_kms_wrapper.c
parent142a309604b65c26ca95594943ee91dde8688697 (diff)
[modesetting-101] Add subconnector and select_subconnector properties.
- These facilitate DVI-I and tv-out that can drive multiple types of signals.
Diffstat (limited to 'linux-core/nv50_kms_wrapper.c')
-rw-r--r--linux-core/nv50_kms_wrapper.c100
1 files changed, 88 insertions, 12 deletions
diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c
index f1f5b69f..ee18b36a 100644
--- a/linux-core/nv50_kms_wrapper.c
+++ b/linux-core/nv50_kms_wrapper.c
@@ -387,7 +387,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
}
connector = to_nv50_connector(drm_connector);
- output = connector->to_output(connector, connector->digital);
+ output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
if (!output) {
DRM_ERROR("No output\n");
goto out;
@@ -447,7 +447,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)
goto out;
}
- output = connector->to_output(connector, connector->digital);
+ output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
if (!output) {
DRM_ERROR("No output\n");
goto out;
@@ -806,6 +806,63 @@ static int nv50_kms_encoders_init(struct drm_device *dev)
* Connector functions
*/
+bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector)
+{
+ struct drm_device *dev = drm_connector->dev;
+
+ switch (drm_connector->connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ case DRM_MODE_CONNECTOR_SVIDEO:
+ return false;
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_LVDS:
+ return true;
+ default:
+ break;
+ }
+
+ if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) {
+ int rval;
+ uint64_t prop_val;
+
+ rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, &prop_val);
+ if (!rval) {
+ DRM_ERROR("Unable to find select subconnector property, defaulting to DVI-D\n");
+ return true;
+ }
+
+ /* Is a subconnector explicitly selected? */
+ switch (prop_val) {
+ case DRM_MODE_SUBCONNECTOR_DVID:
+ return true;
+ case DRM_MODE_SUBCONNECTOR_DVIA:
+ return false;
+ default:
+ break;
+ }
+
+ rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, &prop_val);
+ if (!rval) {
+ DRM_ERROR("Unable to find subconnector property, defaulting to DVI-D\n");
+ return true;
+ }
+
+ /* Do we know what subconnector we currently have connected? */
+ switch (prop_val) {
+ case DRM_MODE_SUBCONNECTOR_DVID:
+ return true;
+ case DRM_MODE_SUBCONNECTOR_DVIA:
+ return false;
+ default:
+ DRM_ERROR("Unknown subconnector value, defaulting to DVI-D\n");
+ return true;
+ }
+ }
+
+ DRM_ERROR("Unknown connector type, defaulting to analog\n");
+ return false;
+}
+
void nv50_kms_connector_detect_all(struct drm_device *dev)
{
struct drm_connector *drm_connector = NULL;
@@ -867,7 +924,8 @@ static struct drm_display_mode std_mode[] = {
static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, uint32_t maxX, uint32_t maxY)
{
struct nv50_connector *connector = to_nv50_connector(drm_connector);
- int ret = 0;
+ struct drm_device *dev = drm_connector->dev;
+ int rval = 0;
bool connected;
struct drm_display_mode *mode, *t;
struct edid *edid = NULL;
@@ -896,21 +954,32 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
if (edid) {
drm_mode_connector_update_edid_property(drm_connector, edid);
- ret = drm_add_edid_modes(drm_connector, edid);
- connector->digital = edid->digital; /* cache */
+ rval = drm_add_edid_modes(drm_connector, edid);
+
+ /* 2 encoders per connector */
+ /* eventually do this based on load detect and hot plug detect */
+ if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) {
+ uint64_t subtype = 0;
+ if (edid->digital)
+ subtype = DRM_MODE_SUBCONNECTOR_DVID;
+ else
+ subtype = DRM_MODE_SUBCONNECTOR_DVIA;
+ drm_connector_property_set_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, subtype);
+ }
+
kfree(edid);
}
- if (ret) /* number of modes > 1 */
+ if (rval) /* number of modes > 1 */
drm_mode_connector_list_update(drm_connector);
if (maxX && maxY)
- drm_mode_validate_size(drm_connector->dev, &drm_connector->modes, maxX, maxY, 0);
+ drm_mode_validate_size(dev, &drm_connector->modes, maxX, maxY, 0);
list_for_each_entry_safe(mode, t, &drm_connector->modes, head) {
if (mode->status == MODE_OK) {
struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode);
- struct nv50_output *output = connector->to_output(connector, connector->digital);
+ struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
mode->status = output->validate_mode(output, hw_mode);
/* find native mode, TODO: also check if we actually found one */
@@ -926,14 +995,14 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
list_for_each_entry_safe(mode, t, &drm_connector->modes, head) {
if (mode->status == MODE_OK) {
struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode);
- struct nv50_output *output = connector->to_output(connector, connector->digital);
+ struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
mode->status = output->validate_mode(output, hw_mode);
kfree(hw_mode);
}
}
- drm_mode_prune_invalid(drm_connector->dev, &drm_connector->modes, true);
+ drm_mode_prune_invalid(dev, &drm_connector->modes, true);
if (list_empty(&drm_connector->modes)) {
struct drm_display_mode *stdmode;
@@ -947,14 +1016,14 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u
* here and bailed in the past, now we add a standard
* 640x480@60Hz mode and carry on.
*/
- stdmode = drm_mode_duplicate(drm_connector->dev, &std_mode[0]);
+ stdmode = drm_mode_duplicate(dev, &std_mode[0]);
drm_mode_probed_add(drm_connector, stdmode);
drm_mode_list_concat(&drm_connector->probed_modes,
&drm_connector->modes);
/* also add it as native mode */
hw_mode = nv50_kms_to_hw_mode(mode);
- output = connector->to_output(connector, connector->digital);
+ output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector));
if (hw_mode)
*output->native_mode = *hw_mode;
@@ -1045,6 +1114,13 @@ static int nv50_kms_connectors_init(struct drm_device *dev)
drm_connector_init(dev, drm_connector, &nv50_kms_connector_funcs, type);
+ /* Init DVI-I specific properties */
+ if (type == DRM_MODE_CONNECTOR_DVII) {
+ drm_mode_create_dvi_i_properties(dev);
+ drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_subconnector_property, 0);
+ drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, 0);
+ }
+
/* attach encoders, possibilities are analog + digital */
for (i = 0; i < 2; i++) {
struct drm_encoder *drm_encoder = NULL;