Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 282577
b: refs/heads/master
c: b29caa5
h: refs/heads/master
i:
  282575: d753606
v: v3
  • Loading branch information
Ben Skeggs committed Dec 21, 2011
1 parent e34a2d4 commit 140a442
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 52 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 27d5030a235d89842ed70e18d924f017b34a496d
refs/heads/master: b29caa5885e85bbda7c84ea55721b9e79718583a
78 changes: 70 additions & 8 deletions trunk/drivers/gpu/drm/nouveau/nouveau_connector.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,15 +420,21 @@ static int
nouveau_connector_set_property(struct drm_connector *connector,
struct drm_property *property, uint64_t value)
{
struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
struct nouveau_display_engine *disp = &dev_priv->engine.display;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
struct drm_device *dev = connector->dev;
struct nouveau_crtc *nv_crtc;
int ret;

nv_crtc = NULL;
if (connector->encoder && connector->encoder->crtc)
nv_crtc = nouveau_crtc(connector->encoder->crtc);

/* Scaling mode */
if (property == dev->mode_config.scaling_mode_property) {
struct nouveau_crtc *nv_crtc = NULL;
bool modeset = false;

switch (value) {
Expand All @@ -454,8 +460,6 @@ nouveau_connector_set_property(struct drm_connector *connector,
modeset = true;
nv_connector->scaling_mode = value;

if (connector->encoder && connector->encoder->crtc)
nv_crtc = nouveau_crtc(connector->encoder->crtc);
if (!nv_crtc)
return 0;

Expand All @@ -475,18 +479,56 @@ nouveau_connector_set_property(struct drm_connector *connector,
return 0;
}

/* Underscan */
if (property == disp->underscan_property) {
if (nv_connector->underscan != value) {
nv_connector->underscan = value;
if (!nv_crtc || !nv_crtc->set_scale)
return 0;

return nv_crtc->set_scale(nv_crtc,
nv_connector->scaling_mode,
true);
}

return 0;
}

if (property == disp->underscan_hborder_property) {
if (nv_connector->underscan_hborder != value) {
nv_connector->underscan_hborder = value;
if (!nv_crtc || !nv_crtc->set_scale)
return 0;

return nv_crtc->set_scale(nv_crtc,
nv_connector->scaling_mode,
true);
}

return 0;
}

if (property == disp->underscan_vborder_property) {
if (nv_connector->underscan_vborder != value) {
nv_connector->underscan_vborder = value;
if (!nv_crtc || !nv_crtc->set_scale)
return 0;

return nv_crtc->set_scale(nv_crtc,
nv_connector->scaling_mode,
true);
}

return 0;
}

/* Dithering */
if (property == dev->mode_config.dithering_mode_property) {
struct nouveau_crtc *nv_crtc = NULL;

if (value == DRM_MODE_DITHERING_ON)
nv_connector->use_dithering = true;
else
nv_connector->use_dithering = false;

if (connector->encoder && connector->encoder->crtc)
nv_crtc = nouveau_crtc(connector->encoder->crtc);

if (!nv_crtc || !nv_crtc->set_dither)
return 0;

Expand Down Expand Up @@ -773,6 +815,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
{
const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_display_engine *disp = &dev_priv->engine.display;
struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
struct nouveau_connector *nv_connector = NULL;
struct dcb_connector_table_entry *dcb = NULL;
Expand Down Expand Up @@ -857,6 +900,25 @@ nouveau_connector_create(struct drm_device *dev, int index)
drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0);
}

/* Add overscan compensation options to digital outputs */
if ((dev_priv->card_type == NV_50 ||
dev_priv->card_type == NV_C0) &&
(dcb->type == DCB_CONNECTOR_DVI_D ||
dcb->type == DCB_CONNECTOR_DVI_I ||
dcb->type == DCB_CONNECTOR_HDMI_0 ||
dcb->type == DCB_CONNECTOR_HDMI_1 ||
dcb->type == DCB_CONNECTOR_DP)) {
drm_connector_attach_property(connector,
disp->underscan_property,
UNDERSCAN_OFF);
drm_connector_attach_property(connector,
disp->underscan_hborder_property,
0);
drm_connector_attach_property(connector,
disp->underscan_vborder_property,
0);
}

switch (dcb->type) {
case DCB_CONNECTOR_VGA:
if (dev_priv->card_type >= NV_50) {
Expand Down
5 changes: 4 additions & 1 deletion trunk/drivers/gpu/drm/nouveau/nouveau_connector.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ struct nouveau_connector {

struct dcb_connector_table_entry *dcb;

int scaling_mode;
bool use_dithering;
int scaling_mode;
enum nouveau_underscan_type underscan;
u32 underscan_hborder;
u32 underscan_vborder;

struct nouveau_encoder *detected_encoder;
struct edid *edid;
Expand Down
35 changes: 34 additions & 1 deletion trunk/drivers/gpu/drm/nouveau/nouveau_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,50 @@ static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
.output_poll_changed = nouveau_fbcon_output_poll_changed,
};


struct drm_prop_enum_list {
int type;
char *name;
};

static struct drm_prop_enum_list nouveau_underscan_enum_list[] = {
{ UNDERSCAN_OFF, "off" },
{ UNDERSCAN_ON, "on" },
{ UNDERSCAN_AUTO, "auto" },
};

int
nouveau_display_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_display_engine *disp = &dev_priv->engine.display;
int ret;
int ret, cnt, i;

drm_mode_config_init(dev);
drm_mode_create_scaling_mode_property(dev);
drm_mode_create_dithering_property(dev);

cnt = ARRAY_SIZE(nouveau_underscan_enum_list);
disp->underscan_property = drm_property_create(dev, DRM_MODE_PROP_ENUM,
"underscan", cnt);
for (i = 0; i < cnt; i++) {
drm_property_add_enum(disp->underscan_property, i,
nouveau_underscan_enum_list[i].type,
nouveau_underscan_enum_list[i].name);
}

disp->underscan_hborder_property =
drm_property_create(dev, DRM_MODE_PROP_RANGE,
"underscan hborder", 2);
disp->underscan_hborder_property->values[0] = 0;
disp->underscan_hborder_property->values[1] = 128;

disp->underscan_vborder_property =
drm_property_create(dev, DRM_MODE_PROP_RANGE,
"underscan vborder", 2);
disp->underscan_vborder_property->values[0] = 0;
disp->underscan_vborder_property->values[1] = 128;

dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);

Expand Down
10 changes: 10 additions & 0 deletions trunk/drivers/gpu/drm/nouveau/nouveau_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,13 +391,23 @@ struct nouveau_fifo_engine {
void (*tlb_flush)(struct drm_device *dev);
};

enum nouveau_underscan_type {
UNDERSCAN_OFF,
UNDERSCAN_ON,
UNDERSCAN_AUTO,
};

struct nouveau_display_engine {
void *priv;
int (*early_init)(struct drm_device *);
void (*late_takedown)(struct drm_device *);
int (*create)(struct drm_device *);
int (*init)(struct drm_device *);
void (*destroy)(struct drm_device *);

struct drm_property *underscan_property;
struct drm_property *underscan_hborder_property;
struct drm_property *underscan_vborder_property;
};

struct nouveau_gpio_engine {
Expand Down
99 changes: 58 additions & 41 deletions trunk/drivers/gpu/drm/nouveau/nv50_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,74 +215,91 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
static int
nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update)
{
struct nouveau_connector *nv_connector =
nouveau_crtc_connector_get(nv_crtc);
struct nouveau_connector *nv_connector;
struct drm_crtc *crtc = &nv_crtc->base;
struct drm_device *dev = crtc->dev;
struct nouveau_channel *evo = nv50_display(dev)->master;
struct drm_display_mode *native_mode = NULL;
struct drm_display_mode *mode = &crtc->mode;
uint32_t outX, outY, horiz, vert;
u32 ctrl = 0, oX, oY;
int ret;

NV_DEBUG_KMS(dev, "\n");

switch (scaling_mode) {
case DRM_MODE_SCALE_NONE:
break;
default:
if (!nv_connector || !nv_connector->native_mode) {
NV_ERROR(dev, "No native mode, forcing panel scaling\n");
scaling_mode = DRM_MODE_SCALE_NONE;
nv_connector = nouveau_crtc_connector_get(nv_crtc);
if (!nv_connector || !nv_connector->native_mode) {
NV_ERROR(dev, "no native mode, forcing panel scaling\n");
scaling_mode = DRM_MODE_SCALE_NONE;
}

/* start off at the resolution we programmed the crtc for, this
* effectively handles NONE/FULL scaling
*/
if (scaling_mode != DRM_MODE_SCALE_NONE) {
oX = nv_connector->native_mode->hdisplay;
oY = nv_connector->native_mode->vdisplay;
} else {
oX = mode->hdisplay;
oY = mode->vdisplay;
}

/* add overscan compensation if necessary, will keep the aspect
* ratio the same as the backend mode unless overridden by the
* user setting both hborder and vborder properties.
*/
if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
(nv_connector->underscan == UNDERSCAN_AUTO &&
nv_connector->edid &&
drm_detect_hdmi_monitor(nv_connector->edid)))) {
u32 bX = nv_connector->underscan_hborder;
u32 bY = nv_connector->underscan_vborder;
u32 aspect = (oY << 19) / oX;

if (bX) {
oX -= (bX * 2);
if (bY) oY -= (bY * 2);
else oY = ((oX * aspect) + (aspect / 2)) >> 19;
} else {
native_mode = nv_connector->native_mode;
oX -= (oX >> 4) + 32;
if (bY) oY -= (bY * 2);
else oY = ((oX * aspect) + (aspect / 2)) >> 19;
}
break;
}

/* handle CENTER/ASPECT scaling, taking into account the areas
* removed already for overscan compensation
*/
switch (scaling_mode) {
case DRM_MODE_SCALE_CENTER:
oX = min((u32)mode->hdisplay, oX);
oY = min((u32)mode->vdisplay, oY);
/* fall-through */
case DRM_MODE_SCALE_ASPECT:
horiz = (native_mode->hdisplay << 19) / mode->hdisplay;
vert = (native_mode->vdisplay << 19) / mode->vdisplay;

if (vert > horiz) {
outX = (mode->hdisplay * horiz) >> 19;
outY = (mode->vdisplay * horiz) >> 19;
if (oY < oX) {
u32 aspect = (mode->hdisplay << 19) / mode->vdisplay;
oX = ((oY * aspect) + (aspect / 2)) >> 19;
} else {
outX = (mode->hdisplay * vert) >> 19;
outY = (mode->vdisplay * vert) >> 19;
u32 aspect = (mode->vdisplay << 19) / mode->hdisplay;
oY = ((oX * aspect) + (aspect / 2)) >> 19;
}
break;
case DRM_MODE_SCALE_FULLSCREEN:
outX = native_mode->hdisplay;
outY = native_mode->vdisplay;
break;
case DRM_MODE_SCALE_CENTER:
case DRM_MODE_SCALE_NONE:
default:
outX = mode->hdisplay;
outY = mode->vdisplay;
break;
}

if (mode->hdisplay != oX || mode->vdisplay != oY ||
mode->flags & DRM_MODE_FLAG_INTERLACE ||
mode->flags & DRM_MODE_FLAG_DBLSCAN)
ctrl |= NV50_EVO_CRTC_SCALE_CTRL_ACTIVE;

ret = RING_SPACE(evo, 5);
if (ret)
return ret;

/* Got a better name for SCALER_ACTIVE? */
/* One day i've got to really figure out why this is needed. */
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_CTRL), 1);
if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) ||
(mode->flags & DRM_MODE_FLAG_INTERLACE) ||
mode->hdisplay != outX || mode->vdisplay != outY) {
OUT_RING(evo, NV50_EVO_CRTC_SCALE_CTRL_ACTIVE);
} else {
OUT_RING(evo, NV50_EVO_CRTC_SCALE_CTRL_INACTIVE);
}

OUT_RING (evo, ctrl);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_RES1), 2);
OUT_RING(evo, outY << 16 | outX);
OUT_RING(evo, outY << 16 | outX);
OUT_RING (evo, oY << 16 | oX);
OUT_RING (evo, oY << 16 | oX);

if (update) {
nv50_display_flip_stop(crtc);
Expand Down

0 comments on commit 140a442

Please sign in to comment.