diff options
| author | Maarten Maathuis <madman2003@gmail.com> | 2008-07-20 13:49:18 +0200 | 
|---|---|---|
| committer | Maarten Maathuis <madman2003@gmail.com> | 2008-07-20 13:49:18 +0200 | 
| commit | 65803e53a696347e38d7f6c2c8dc186c6764ff03 (patch) | |
| tree | 18fe7abbb93a8fa76529c099db4f214a82fe654b /linux-core | |
| parent | e2ffee839ed7ae6c55a0a8c6bb8ee872ae8a2a70 (diff) | |
modesetting-101: implement optional scaling and dithering properties
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/drm_crtc.c | 69 | ||||
| -rw-r--r-- | linux-core/drm_crtc.h | 8 | ||||
| -rw-r--r-- | linux-core/nv50_connector.c | 4 | ||||
| -rw-r--r-- | linux-core/nv50_connector.h | 1 | ||||
| -rw-r--r-- | linux-core/nv50_crtc.c | 2 | ||||
| -rw-r--r-- | linux-core/nv50_display.h | 2 | ||||
| -rw-r--r-- | linux-core/nv50_kms_wrapper.c | 128 | 
7 files changed, 205 insertions, 9 deletions
| diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fc8d1fe8..c984209a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -60,6 +60,26 @@ char *drm_get_dpms_name(int val)  	return "unknown";  } +/* + * Optional properties + */ +static struct drm_prop_enum_list drm_scaling_mode_enum_list[] = +{ +	{ DRM_MODE_SCALE_NON_GPU, "Non-GPU" }, +	{ DRM_MODE_SCALE_FULLSCREEN, "Fullscreen" }, +	{ DRM_MODE_SCALE_NO_SCALE, "No scale" }, +	{ DRM_MODE_SCALE_ASPECT, "Aspect" }, +}; + +static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = +{ +	{ DRM_MODE_DITHERING_OFF, "Off" }, +	{ DRM_MODE_DITHERING_ON, "On" }, +}; + +/* + * Non-global properties, but "required" for certain connectors. + */  static struct drm_prop_enum_list drm_select_subconnector_enum_list[] =  {  	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ @@ -102,6 +122,9 @@ char *drm_get_subconnector_name(int val)  	return "unknown";  } +/* + * Connector and encoder types. + */  static struct drm_prop_enum_list drm_connector_enum_list[] =   {	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },  	{ DRM_MODE_CONNECTOR_VGA, "VGA" }, @@ -647,6 +670,52 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,  EXPORT_SYMBOL(drm_mode_create_tv_properties);  /** + * drm_mode_create_scaling_mode_property - create scaling mode property + * @dev: DRM device + * + * Called by a driver the first time it's needed, must be attached to desired connectors. + */ +int drm_mode_create_scaling_mode_property(struct drm_device *dev) +{ +	int i; + +	if (dev->mode_config.scaling_mode_property) /* already done */ +		return 0; + +	dev->mode_config.scaling_mode_property = +		drm_property_create(dev, DRM_MODE_PROP_ENUM,  +			"scaling mode", ARRAY_SIZE(drm_scaling_mode_enum_list)); +	for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++) +		drm_property_add_enum(dev->mode_config.scaling_mode_property, i, drm_scaling_mode_enum_list[i].type, drm_scaling_mode_enum_list[i].name); + +	return 0; +} +EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); + +/** + * drm_mode_create_dithering_property - create dithering property + * @dev: DRM device + * + * Called by a driver the first time it's needed, must be attached to desired connectors. + */ +int drm_mode_create_dithering_property(struct drm_device *dev) +{ +	int i; + +	if (dev->mode_config.dithering_mode_property) /* already done */ +		return 0; + +	dev->mode_config.dithering_mode_property = +		drm_property_create(dev, DRM_MODE_PROP_ENUM,  +			"dithering", ARRAY_SIZE(drm_dithering_mode_enum_list)); +	for (i = 0; i < ARRAY_SIZE(drm_dithering_mode_enum_list); i++) +		drm_property_add_enum(dev->mode_config.dithering_mode_property, i, drm_dithering_mode_enum_list[i].type, drm_dithering_mode_enum_list[i].name); + +	return 0; +} +EXPORT_SYMBOL(drm_mode_create_dithering_property); + +/**   * drm_mode_config_init - initialize DRM mode_configuration structure   * @dev: DRM device   * diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d4bb8794..d88c6149 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -536,7 +536,7 @@ struct drm_mode_config {  	struct drm_property *edid_property;  	struct drm_property *dpms_property; -	/* optional properties */ +	/* DVI-I properties */  	struct drm_property *dvi_i_subconnector_property;  	struct drm_property *dvi_i_select_subconnector_property; @@ -549,6 +549,10 @@ struct drm_mode_config {  	struct drm_property *tv_top_margin_property;  	struct drm_property *tv_bottom_margin_property; +	/* Optional properties */ +	struct drm_property *scaling_mode_property; +	struct drm_property *dithering_mode_property; +  	/* hotplug */  	uint32_t hotplug_counter;  }; @@ -650,6 +654,8 @@ extern int drm_property_add_enum(struct drm_property *property, int index,  extern int drm_mode_create_dvi_i_properties(struct drm_device *dev);  extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats,  				     char *formats[]); +extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); +extern int drm_mode_create_dithering_property(struct drm_device *dev);  extern char *drm_get_encoder_name(struct drm_encoder *encoder);  extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index ac5194c0..be133de3 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -187,7 +187,9 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty  	if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS)  		connector->scaling_mode = SCALE_FULLSCREEN;  	else -		connector->scaling_mode = SCALE_PANEL; +		connector->scaling_mode = SCALE_NON_GPU; + +	connector->use_dithering = false;  	if (i2c_index < 0xf)  		connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index); diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index ebd6eac6..02b1561e 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -48,6 +48,7 @@ struct nv50_connector {  	struct nv50_output *output;  	int scaling_mode; +	bool use_dithering;  	bool (*detect) (struct nv50_connector *connector);  	int (*destroy) (struct nv50_connector *connector); diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index 6c3d404f..ffb976f4 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -264,7 +264,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc)  			outY = crtc->native_mode->vdisplay;  			break;  		case SCALE_NOSCALE: -		case SCALE_PANEL: +		case SCALE_NON_GPU:  		default:  			outX = crtc->mode->hdisplay;  			outY = crtc->mode->vdisplay; diff --git a/linux-core/nv50_display.h b/linux-core/nv50_display.h index f20e67da..3c2ee1c9 100644 --- a/linux-core/nv50_display.h +++ b/linux-core/nv50_display.h @@ -68,7 +68,7 @@ struct nv50_display {  };  enum scaling_modes { -	SCALE_PANEL, +	SCALE_NON_GPU,  	SCALE_FULLSCREEN,  	SCALE_ASPECT,  	SCALE_NOSCALE, diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index a7966e9a..b0d64340 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -636,10 +636,11 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set)  					continue;  				crtc->scaling_mode = connector->scaling_mode; +				crtc->use_dithering = connector->use_dithering;  				break;  			} -			if (crtc->scaling_mode == SCALE_PANEL) +			if (crtc->scaling_mode == SCALE_NON_GPU)  				crtc->use_native_mode = false;  			else  				crtc->use_native_mode = true; @@ -1078,14 +1079,16 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u  	}  } -static bool nv50_kms_connector_set_property(struct drm_connector *connector, +static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector,  					struct drm_property *property,  					uint64_t value)  { -	struct drm_device *dev = connector->dev; +	struct drm_device *dev = drm_connector->dev; +	struct nv50_connector *connector = to_nv50_connector(drm_connector); -	if (property == dev->mode_config.dpms_property && connector->encoder) { -		struct nv50_output *output = to_nv50_output(connector->encoder); +	/* DPMS */ +	if (property == dev->mode_config.dpms_property && drm_connector->encoder) { +		struct nv50_output *output = to_nv50_output(drm_connector->encoder);  		if (!output->set_power_mode(output, (int) value))  			return true; @@ -1093,6 +1096,78 @@ static bool nv50_kms_connector_set_property(struct drm_connector *connector,  			return false;  	} +	/* Scaling mode */ +	if (property == dev->mode_config.scaling_mode_property) { +		struct nv50_crtc *crtc = NULL; +		struct nv50_display *display = nv50_get_display(dev); +		int internal_value = 0; +		int rval = 0; + +		switch (value) { +			case DRM_MODE_SCALE_NON_GPU: +				internal_value = SCALE_NON_GPU; +				break; +			case DRM_MODE_SCALE_FULLSCREEN: +				internal_value = SCALE_FULLSCREEN; +				break; +			case DRM_MODE_SCALE_NO_SCALE: +				internal_value = SCALE_NOSCALE; +				break; +			case DRM_MODE_SCALE_ASPECT: +				internal_value = SCALE_ASPECT; +				break; +			default: +				break; +		} + +		connector->scaling_mode = internal_value; + +		if (drm_connector->encoder && drm_connector->encoder->crtc) +			crtc = to_nv50_crtc(drm_connector->encoder->crtc); + +		if (!crtc) +			return true; + +		crtc->scaling_mode = connector->scaling_mode; +		rval = crtc->set_scale(crtc); +		if (rval) +			return false; + +		/* process command buffer */ +		display->update(display); + +		return true; +	} + +	/* Dithering */ +	if (property == dev->mode_config.dithering_mode_property) { +		struct nv50_crtc *crtc = NULL; +		struct nv50_display *display = nv50_get_display(dev); +		int rval = 0; + +		if (value == DRM_MODE_DITHERING_ON) +			connector->use_dithering = true; +		else +			connector->use_dithering = false; + +		if (drm_connector->encoder && drm_connector->encoder->crtc) +			crtc = to_nv50_crtc(drm_connector->encoder->crtc); + +		if (!crtc) +			return true; + +		/* update hw state */ +		crtc->use_dithering = connector->use_dithering; +		rval = crtc->set_dither(crtc); +		if (rval) +			return false; + +		/* process command buffer */ +		display->update(display); + +		return true; +	} +  	return false;  } @@ -1105,12 +1180,48 @@ static const struct drm_connector_funcs nv50_kms_connector_funcs = {  	.set_property = nv50_kms_connector_set_property  }; +static int nv50_kms_get_scaling_mode(struct drm_connector *drm_connector) +{ +	struct nv50_connector *connector = NULL; +	int drm_mode = 0; + +	if (!drm_connector) { +		DRM_ERROR("drm_connector is NULL\n"); +		return 0; +	} + +	connector = to_nv50_connector(drm_connector); + +	switch (connector->scaling_mode) { +		case SCALE_NON_GPU: +			drm_mode = DRM_MODE_SCALE_NON_GPU; +			break; +		case SCALE_FULLSCREEN: +			drm_mode = DRM_MODE_SCALE_FULLSCREEN; +			break; +		case SCALE_NOSCALE: +			drm_mode = DRM_MODE_SCALE_NO_SCALE; +			break; +		case SCALE_ASPECT: +			drm_mode = DRM_MODE_SCALE_ASPECT; +			break; +		default: +			break; +	} + +	return drm_mode; +} +  static int nv50_kms_connectors_init(struct drm_device *dev)  {  	struct nv50_display *display = nv50_get_display(dev);  	struct nv50_connector *connector = NULL;  	int i; +	/* Initialise some optional connector properties. */ +	drm_mode_create_scaling_mode_property(dev); +	drm_mode_create_dithering_property(dev); +  	list_for_each_entry(connector, &display->connectors, item) {  		struct drm_connector *drm_connector = to_nv50_kms_connector(connector);  		uint32_t type = DRM_MODE_CONNECTOR_Unknown; @@ -1154,6 +1265,13 @@ static int nv50_kms_connectors_init(struct drm_device *dev)  			drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, 0);  		} +		/* If supported in the future, it will have to use the scalers internally and not expose them. */ +		if (type != DRM_MODE_CONNECTOR_SVIDEO) { +			drm_connector_attach_property(drm_connector, dev->mode_config.scaling_mode_property, nv50_kms_get_scaling_mode(drm_connector)); +		} + +		drm_connector_attach_property(drm_connector, dev->mode_config.dithering_mode_property, connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); +  		/* attach encoders, possibilities are analog + digital */  		for (i = 0; i < 2; i++) {  			struct drm_encoder *drm_encoder = NULL; | 
