modesetting-101: implement optional scaling and dithering properties
parent
e2ffee839e
commit
65803e53a6
|
@ -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" },
|
||||
|
@ -646,6 +669,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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -68,7 +68,7 @@ struct nv50_display {
|
|||
};
|
||||
|
||||
enum scaling_modes {
|
||||
SCALE_PANEL,
|
||||
SCALE_NON_GPU,
|
||||
SCALE_FULLSCREEN,
|
||||
SCALE_ASPECT,
|
||||
SCALE_NOSCALE,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1034,6 +1034,16 @@ struct drm_mm_info_arg {
|
|||
#define DRM_MODE_DPMS_SUSPEND 2
|
||||
#define DRM_MODE_DPMS_OFF 3
|
||||
|
||||
/* Scaling mode options */
|
||||
#define DRM_MODE_SCALE_NON_GPU 0
|
||||
#define DRM_MODE_SCALE_FULLSCREEN 1
|
||||
#define DRM_MODE_SCALE_NO_SCALE 2
|
||||
#define DRM_MODE_SCALE_ASPECT 3
|
||||
|
||||
/* Dithering mode options */
|
||||
#define DRM_MODE_DITHERING_OFF 0
|
||||
#define DRM_MODE_DITHERING_ON 1
|
||||
|
||||
struct drm_mode_modeinfo {
|
||||
unsigned int clock;
|
||||
unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew;
|
||||
|
|
Loading…
Reference in New Issue