Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

drm/nouveau: improve dithering properties, and implement proper auto mode



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 488ff207
Loading
Loading
Loading
Loading
+23 −14
Original line number Diff line number Diff line
@@ -517,12 +517,16 @@ nouveau_connector_set_property(struct drm_connector *connector,
	}

	/* Dithering */
	if (property == dev->mode_config.dithering_mode_property) {
		if (value == DRM_MODE_DITHERING_ON)
			nv_connector->use_dithering = true;
		else
			nv_connector->use_dithering = false;
	if (property == disp->dithering_mode) {
		nv_connector->dithering_mode = value;
		if (!nv_crtc || !nv_crtc->set_dither)
			return 0;

		return nv_crtc->set_dither(nv_crtc, true);
	}

	if (property == disp->dithering_depth) {
		nv_connector->dithering_depth = value;
		if (!nv_crtc || !nv_crtc->set_dither)
			return 0;

@@ -918,7 +922,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
	drm_connector_init(dev, connector, funcs, type);
	drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);

	/* Check if we need dithering enabled */
	/* parse lvds table now, we depend on bios->fp.* values later */
	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
		bool dummy, is_24bit = false;

@@ -928,8 +932,6 @@ nouveau_connector_create(struct drm_device *dev, int index)
				 "LVDS\n");
			goto fail;
		}

		nv_connector->use_dithering = !is_24bit;
	}

	/* Init DVI-I specific properties */
@@ -940,8 +942,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
	}

	/* Add overscan compensation options to digital outputs */
	if ((dev_priv->card_type == NV_50 ||
	     dev_priv->card_type == NV_C0) &&
	if (disp->underscan_property &&
	    (dcb->type == DCB_CONNECTOR_DVI_D ||
	     dcb->type == DCB_CONNECTOR_DVI_I ||
	     dcb->type == DCB_CONNECTOR_HDMI_0 ||
@@ -977,10 +978,18 @@ nouveau_connector_create(struct drm_device *dev, int index)
		drm_connector_attach_property(connector,
				dev->mode_config.scaling_mode_property,
				nv_connector->scaling_mode);
		if (disp->dithering_mode) {
			nv_connector->dithering_mode = DITHERING_MODE_AUTO;
			drm_connector_attach_property(connector,
				dev->mode_config.dithering_mode_property,
				nv_connector->use_dithering ?
				DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
						disp->dithering_mode,
						nv_connector->dithering_mode);
		}
		if (disp->dithering_depth) {
			nv_connector->dithering_depth = DITHERING_DEPTH_AUTO;
			drm_connector_attach_property(connector,
						disp->dithering_depth,
						nv_connector->dithering_depth);
		}
		break;
	}

+26 −1
Original line number Diff line number Diff line
@@ -30,12 +30,37 @@
#include "drm_edid.h"
#include "nouveau_i2c.h"

enum nouveau_underscan_type {
	UNDERSCAN_OFF,
	UNDERSCAN_ON,
	UNDERSCAN_AUTO,
};

/* the enum values specifically defined here match nv50/nvd0 hw values, and
 * the code relies on this
 */
enum nouveau_dithering_mode {
	DITHERING_MODE_OFF = 0x00,
	DITHERING_MODE_ON = 0x01,
	DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON,
	DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON,
	DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON,
	DITHERING_MODE_AUTO
};

enum nouveau_dithering_depth {
	DITHERING_DEPTH_6BPC = 0x00,
	DITHERING_DEPTH_8BPC = 0x02,
	DITHERING_DEPTH_AUTO
};

struct nouveau_connector {
	struct drm_connector base;

	struct dcb_connector_table_entry *dcb;

	bool use_dithering;
	int dithering_mode;
	int dithering_depth;
	int scaling_mode;
	enum nouveau_underscan_type underscan;
	u32 underscan_hborder;
+59 −15
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include "nouveau_hw.h"
#include "nouveau_crtc.h"
#include "nouveau_dma.h"
#include "nouveau_connector.h"
#include "nv50_display.h"

static void
@@ -154,35 +155,78 @@ static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {


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

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

static struct drm_prop_enum_list dither_mode[] = {
	{ 7, DITHERING_MODE_AUTO, "auto" },
	{ 7, DITHERING_MODE_OFF, "off" },
	{ 1, DITHERING_MODE_ON, "on" },
	{ 6, DITHERING_MODE_STATIC2X2, "static 2x2" },
	{ 6, DITHERING_MODE_DYNAMIC2X2, "dynamic 2x2" },
	{ 4, DITHERING_MODE_TEMPORAL, "temporal" },
	{}
};

static struct drm_prop_enum_list dither_depth[] = {
	{ 6, DITHERING_DEPTH_AUTO, "auto" },
	{ 6, DITHERING_DEPTH_6BPC, "6 bpc" },
	{ 6, DITHERING_DEPTH_8BPC, "8 bpc" },
	{}
};

#define PROP_ENUM(p,gen,n,list) do {                                           \
	struct drm_prop_enum_list *l = (list);                                 \
	int c = 0;                                                             \
	while (l->gen_mask) {                                                  \
		if (l->gen_mask & (1 << (gen)))                                \
			c++;                                                   \
		l++;                                                           \
	}                                                                      \
	if (c) {                                                               \
		p = drm_property_create(dev, DRM_MODE_PROP_ENUM, n, c);        \
		l = (list);                                                    \
		c = 0;                                                         \
		while (p && l->gen_mask) {                                     \
			if (l->gen_mask & (1 << (gen))) {                      \
				drm_property_add_enum(p, c, l->type, l->name); \
				c++;                                           \
			}                                                      \
			l++;                                                   \
		}                                                              \
	}                                                                      \
} while(0)

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, cnt, i;
	int ret, gen;

	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);
	}

	if (dev_priv->card_type < NV_50)
		gen = 0;
	else
	if (dev_priv->card_type < NV_D0)
		gen = 1;
	else
		gen = 2;

	PROP_ENUM(disp->dithering_mode, gen, "dithering mode", dither_mode);
	PROP_ENUM(disp->dithering_depth, gen, "dithering depth", dither_depth);
	PROP_ENUM(disp->underscan_property, gen, "underscan", underscan);

	disp->underscan_hborder_property =
		drm_property_create(dev, DRM_MODE_PROP_RANGE,
+2 −6
Original line number Diff line number Diff line
@@ -391,12 +391,6 @@ 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 *);
@@ -405,6 +399,8 @@ struct nouveau_display_engine {
	int (*init)(struct drm_device *);
	void (*destroy)(struct drm_device *);

	struct drm_property *dithering_mode;
	struct drm_property *dithering_depth;
	struct drm_property *underscan_property;
	struct drm_property *underscan_hborder_property;
	struct drm_property *underscan_vborder_property;
+4 −1
Original line number Diff line number Diff line
@@ -289,6 +289,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
	struct nouveau_connector *nv_connector = nouveau_crtc_connector_get(nv_crtc);
	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
	struct drm_display_mode *output_mode = &nv_encoder->mode;
	struct drm_connector *connector = &nv_connector->base;
	uint32_t mode_ratio, panel_ratio;

	NV_DEBUG_KMS(dev, "Output mode on CRTC %d:\n", nv_crtc->index);
@@ -407,7 +408,9 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
	}

	/* Output property. */
	if (nv_connector->use_dithering) {
	if ((nv_connector->dithering_mode == DITHERING_MODE_ON) ||
	    (nv_connector->dithering_mode == DITHERING_MODE_AUTO &&
	     encoder->crtc->fb->depth > connector->display_info.bpc * 3)) {
		if (dev_priv->chipset == 0x11)
			regp->dither = savep->dither | 0x00010000;
		else {
Loading