Commit 92854622 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nvd0/disp: scaler updates, overscan compensation etc



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 2d1d898b
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -161,9 +161,9 @@ struct drm_prop_enum_list {
};

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

+64 −30
Original line number Diff line number Diff line
@@ -160,49 +160,83 @@ nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
static int
nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
{
	struct drm_display_mode *mode = &nv_crtc->base.mode;
	struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
	struct drm_device *dev = nv_crtc->base.dev;
	struct nouveau_connector *nv_connector;
	u32 *push, outX, outY;

	outX = mode->hdisplay;
	outY = mode->vdisplay;
	int mode = DRM_MODE_SCALE_NONE;
	u32 oX, oY, *push;

	/* start off at the resolution we programmed the crtc for, this
	 * effectively handles NONE/FULL scaling
	 */
	nv_connector = nouveau_crtc_connector_get(nv_crtc);
	if (nv_connector && nv_connector->native_mode) {
		struct drm_display_mode *native = nv_connector->native_mode;
		u32 xratio = (native->hdisplay << 19) / mode->hdisplay;
		u32 yratio = (native->vdisplay << 19) / mode->vdisplay;
	if (nv_connector && nv_connector->native_mode)
		mode = nv_connector->scaling_mode;

	if (mode != DRM_MODE_SCALE_NONE)
		omode = nv_connector->native_mode;
	else
		omode = umode;

	oX = omode->hdisplay;
	oY = omode->vdisplay;
	if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
		oY *= 2;

	/* 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 {
			oX -= (oX >> 4) + 32;
			if (bY) oY -= (bY * 2);
			else    oY  = ((oX * aspect) + (aspect / 2)) >> 19;
		}
	}

		switch (nv_connector->scaling_mode) {
	/* handle CENTER/ASPECT scaling, taking into account the areas
	 * removed already for overscan compensation
	 */
	switch (mode) {
	case DRM_MODE_SCALE_CENTER:
		oX = min((u32)umode->hdisplay, oX);
		oY = min((u32)umode->vdisplay, oY);
		/* fall-through */
	case DRM_MODE_SCALE_ASPECT:
			if (xratio > yratio) {
				outX = (mode->hdisplay * yratio) >> 19;
				outY = (mode->vdisplay * yratio) >> 19;
		if (oY < oX) {
			u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
			oX = ((oY * aspect) + (aspect / 2)) >> 19;
		} else {
				outX = (mode->hdisplay * xratio) >> 19;
				outY = (mode->vdisplay * xratio) >> 19;
			u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
			oY = ((oX * aspect) + (aspect / 2)) >> 19;
		}
		break;
		case DRM_MODE_SCALE_FULLSCREEN:
			outX = native->hdisplay;
			outY = native->vdisplay;
			break;
	default:
		break;
	}
	}

	push = evo_wait(dev, 0, 16);
	if (push) {
		evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
		evo_data(push, (outY << 16) | outX);
		evo_data(push, (outY << 16) | outX);
		evo_data(push, (outY << 16) | outX);
		evo_data(push, (oY << 16) | oX);
		evo_data(push, (oY << 16) | oX);
		evo_data(push, (oY << 16) | oX);
		evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
		evo_data(push, 0x00000000);
		evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
		evo_data(push, (mode->vdisplay << 16) | mode->hdisplay);
		evo_data(push, (umode->vdisplay << 16) | umode->hdisplay);
		if (update) {
			evo_mthd(push, 0x0080, 1);
			evo_data(push, 0x00000000);