rpms/kernel/F-12 drm-nouveau.patch, 1.68, 1.69 kernel.spec, 1.1943, 1.1944

Ben Skeggs bskeggs at fedoraproject.org
Tue Dec 1 23:24:15 UTC 2009


Author: bskeggs

Update of /cvs/pkgs/rpms/kernel/F-12
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv22138

Modified Files:
	drm-nouveau.patch kernel.spec 
Log Message:
* Wed Dec 02 2009 Ben Skeggs <bskeggs at redhat.com> 2.6.31.6-158
- nouveau: more complete lvds script selection on >=G80 (rh#522690, rh#529859)
- nouveau: more complete tmds script selection on >=G80 (rh#537853)
- nouveau: TV detection fixes



drm-nouveau.patch:
 drivers/gpu/drm/Kconfig                     |   56 
 drivers/gpu/drm/Makefile                    |    2 
 drivers/gpu/drm/i2c/Makefile                |    4 
 drivers/gpu/drm/i2c/ch7006_drv.c            |  531 
 drivers/gpu/drm/i2c/ch7006_mode.c           |  473 
 drivers/gpu/drm/i2c/ch7006_priv.h           |  344 
 drivers/gpu/drm/nouveau/Makefile            |   30 
 drivers/gpu/drm/nouveau/nouveau_acpi.c      |  125 
 drivers/gpu/drm/nouveau/nouveau_backlight.c |  155 
 drivers/gpu/drm/nouveau/nouveau_bios.c      | 5988 ++++++
 drivers/gpu/drm/nouveau/nouveau_bios.h      |  280 
 drivers/gpu/drm/nouveau/nouveau_bo.c        |  663 
 drivers/gpu/drm/nouveau/nouveau_calc.c      |  469 
 drivers/gpu/drm/nouveau/nouveau_channel.c   |  468 
 drivers/gpu/drm/nouveau/nouveau_connector.c |  812 
 drivers/gpu/drm/nouveau/nouveau_connector.h |   54 
 drivers/gpu/drm/nouveau/nouveau_crtc.h      |   95 
 drivers/gpu/drm/nouveau/nouveau_debugfs.c   |  155 
 drivers/gpu/drm/nouveau/nouveau_display.c   |  115 
 drivers/gpu/drm/nouveau/nouveau_dma.c       |  206 
 drivers/gpu/drm/nouveau/nouveau_dma.h       |  157 
 drivers/gpu/drm/nouveau/nouveau_drv.c       |  413 
 drivers/gpu/drm/nouveau/nouveau_drv.h       | 1299 +
 drivers/gpu/drm/nouveau/nouveau_encoder.h   |   66 
 drivers/gpu/drm/nouveau/nouveau_fb.h        |   47 
 drivers/gpu/drm/nouveau/nouveau_fbcon.c     |  380 
 drivers/gpu/drm/nouveau/nouveau_fbcon.h     |   47 
 drivers/gpu/drm/nouveau/nouveau_fence.c     |  262 
 drivers/gpu/drm/nouveau/nouveau_gem.c       |  976 +
 drivers/gpu/drm/nouveau/nouveau_hw.c        | 1078 +
 drivers/gpu/drm/nouveau/nouveau_hw.h        |  448 
 drivers/gpu/drm/nouveau/nouveau_i2c.c       |  257 
 drivers/gpu/drm/nouveau/nouveau_i2c.h       |   45 
 drivers/gpu/drm/nouveau/nouveau_ioc32.c     |   72 
 drivers/gpu/drm/nouveau/nouveau_irq.c       |  696 
 drivers/gpu/drm/nouveau/nouveau_mem.c       |  585 
 drivers/gpu/drm/nouveau/nouveau_notifier.c  |  196 
 drivers/gpu/drm/nouveau/nouveau_object.c    | 1294 +
 drivers/gpu/drm/nouveau/nouveau_reg.h       |  788 
 drivers/gpu/drm/nouveau/nouveau_sgdma.c     |  321 
 drivers/gpu/drm/nouveau/nouveau_state.c     |  876 
 drivers/gpu/drm/nouveau/nouveau_ttm.c       |  131 
 drivers/gpu/drm/nouveau/nv04_crtc.c         | 1001 +
 drivers/gpu/drm/nouveau/nv04_cursor.c       |   70 
 drivers/gpu/drm/nouveau/nv04_dac.c          |  528 
 drivers/gpu/drm/nouveau/nv04_dfp.c          |  621 
 drivers/gpu/drm/nouveau/nv04_display.c      |  293 
 drivers/gpu/drm/nouveau/nv04_fb.c           |   21 
 drivers/gpu/drm/nouveau/nv04_fbcon.c        |  316 
 drivers/gpu/drm/nouveau/nv04_fifo.c         |  271 
 drivers/gpu/drm/nouveau/nv04_graph.c        |  579 
 drivers/gpu/drm/nouveau/nv04_instmem.c      |  210 
 drivers/gpu/drm/nouveau/nv04_mc.c           |   20 
 drivers/gpu/drm/nouveau/nv04_timer.c        |   51 
 drivers/gpu/drm/nouveau/nv04_tv.c           |  305 
 drivers/gpu/drm/nouveau/nv10_fb.c           |   24 
 drivers/gpu/drm/nouveau/nv10_fifo.c         |  260 
 drivers/gpu/drm/nouveau/nv10_graph.c        |  892 
 drivers/gpu/drm/nouveau/nv17_gpio.c         |   92 
 drivers/gpu/drm/nouveau/nv17_tv.c           |  681 
 drivers/gpu/drm/nouveau/nv17_tv.h           |  156 
 drivers/gpu/drm/nouveau/nv17_tv_modes.c     |  583 
 drivers/gpu/drm/nouveau/nv20_graph.c        |  780 
 drivers/gpu/drm/nouveau/nv40_fb.c           |   62 
 drivers/gpu/drm/nouveau/nv40_fifo.c         |  314 
 drivers/gpu/drm/nouveau/nv40_graph.c        | 2239 ++
 drivers/gpu/drm/nouveau/nv40_mc.c           |   38 
 drivers/gpu/drm/nouveau/nv50_crtc.c         |  788 
 drivers/gpu/drm/nouveau/nv50_cursor.c       |  153 
 drivers/gpu/drm/nouveau/nv50_dac.c          |  304 
 drivers/gpu/drm/nouveau/nv50_display.c      |  994 +
 drivers/gpu/drm/nouveau/nv50_display.h      |   46 
 drivers/gpu/drm/nouveau/nv50_evo.h          |  113 
 drivers/gpu/drm/nouveau/nv50_fbcon.c        |  273 
 drivers/gpu/drm/nouveau/nv50_fifo.c         |  494 
 drivers/gpu/drm/nouveau/nv50_graph.c        |  479 
 drivers/gpu/drm/nouveau/nv50_grctx.h        |26832 ++++++++++++++++++++++++++++
 drivers/gpu/drm/nouveau/nv50_instmem.c      |  509 
 drivers/gpu/drm/nouveau/nv50_mc.c           |   40 
 drivers/gpu/drm/nouveau/nv50_sor.c          |  269 
 drivers/gpu/drm/nouveau/nvreg.h             |  535 
 drivers/gpu/drm/ttm/ttm_bo.c                |    4 
 include/drm/Kbuild                          |    1 
 include/drm/i2c/ch7006.h                    |   86 
 include/drm/nouveau_drm.h                   |  220 
 85 files changed, 64006 insertions(+)

Index: drm-nouveau.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-12/drm-nouveau.patch,v
retrieving revision 1.68
retrieving revision 1.69
diff -u -p -r1.68 -r1.69
--- drm-nouveau.patch	19 Nov 2009 00:26:21 -0000	1.68
+++ drm-nouveau.patch	1 Dec 2009 23:24:14 -0000	1.69
@@ -1,8 +1,8 @@
 diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
-index f831ea1..a2320ac 100644
+index e4d971c..62dd13c 100644
 --- a/drivers/gpu/drm/Kconfig
 +++ b/drivers/gpu/drm/Kconfig
-@@ -154,3 +154,59 @@ config DRM_SAVAGE
+@@ -153,3 +153,59 @@ config DRM_SAVAGE
  	help
  	  Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
  	  chipset. If M is selected the module will be called savage.
@@ -1450,10 +1450,10 @@ index 0000000..b06d3d9
 +#endif
 diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
 new file mode 100644
-index 0000000..e12b4ff
+index 0000000..fd75226
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/Makefile
-@@ -0,0 +1,29 @@
+@@ -0,0 +1,30 @@
 +#
 +# Makefile for the drm device driver.  This driver provides support for the
 +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
@@ -1475,7 +1475,8 @@ index 0000000..e12b4ff
 +             nv50_crtc.o nv50_dac.o nv50_sor.o \
 +             nv50_cursor.o nv50_display.o nv50_fbcon.o \
 +             nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
-+             nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o
++             nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
++             nv17_gpio.o
 +
 +nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
 +nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
@@ -1777,10 +1778,10 @@ index 0000000..20564f8
 +}
 diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
 new file mode 100644
-index 0000000..ba946df
+index 0000000..6ddeca2
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
-@@ -0,0 +1,5734 @@
+@@ -0,0 +1,5988 @@
 +/*
 + * Copyright 2005-2006 Erik Waling
 + * Copyright 2006 Stephane Marchesin
@@ -4309,6 +4310,19 @@ index 0000000..ba946df
 +}
 +
 +static bool
++init_8c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
++{
++	/*
++	 * INIT_85   opcode: 0x8C ('')
++	 *
++	 * NOP so far....
++	 *
++	 */
++
++	return true;
++}
++
++static bool
 +init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 +{
 +	/*
@@ -4322,7 +4336,7 @@ index 0000000..ba946df
 +
 +	const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
 +	const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
-+	const uint8_t *gpio_table = &bios->data[bios->bdcb.init8e_table_ptr];
++	const uint8_t *gpio_table = &bios->data[bios->bdcb.gpio_table_ptr];
 +	const uint8_t *gpio_entry;
 +	int i;
 +
@@ -4331,7 +4345,7 @@ index 0000000..ba946df
 +		return false;
 +	}
 +
-+	if (!bios->bdcb.init8e_table_ptr) {
++	if (!bios->bdcb.gpio_table_ptr) {
 +		NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n");
 +		return false;
 +	}
@@ -4753,6 +4767,7 @@ index 0000000..ba946df
 +	{ "INIT_ZM_REG"                       , 0x7A, 9       , 0       , 0       , init_zm_reg                     },
 +	/* INIT_RAM_RESTRICT_PLL's length is adjusted by the BIT M table */
 +	{ "INIT_RAM_RESTRICT_PLL"             , 0x87, 2       , 0       , 0       , init_ram_restrict_pll           },
++	{ "INIT_8C"                           , 0x8C, 1       , 0       , 0       , init_8c                         },
 +	{ "INIT_GPIO"                         , 0x8E, 1       , 0       , 0       , init_gpio                       },
 +	/* INIT_RAM_RESTRICT_ZM_REG_GROUP's mult is loaded by M table in BIT */
 +	{ "INIT_RAM_RESTRICT_ZM_REG_GROUP"    , 0x8F, 7       , 6       , 0       , init_ram_restrict_zm_reg_group  },
@@ -5423,7 +5438,9 @@ index 0000000..ba946df
 +		bios->fp.duallink_transition_clk = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 5]) * 10;
 +		break;
 +	case 0x40:
-+		/* bios->fp.dual_link = bios->data[lvdsofs] & 1; */
++		bios->fp.dual_link = bios->data[lvdsofs] & 1;
++		bios->fp.if_is_24bit = bios->data[lvdsofs] & 2;
++		bios->fp.strapless_is_24bit = bios->data[bios->fp.lvdsmanufacturerpointer + 4];
 +		bios->fp.duallink_transition_clk = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 5]) * 10;
 +		break;
 +	}
@@ -6255,7 +6272,9 @@ index 0000000..ba946df
 +	return 0;
 +}
 +
-+static int parse_bit_M_tbl_entry(struct drm_device *dev, struct nvbios *bios, struct bit_entry *bitentry)
++static int
++parse_bit_M_tbl_entry(struct drm_device *dev, struct nvbios *bios,
++		      struct bit_entry *bitentry)
 +{
 +	/*
 +	 * offset + 2  (8  bits): number of options in an
@@ -6267,6 +6286,8 @@ index 0000000..ba946df
 +	 * stuff that we don't use - their use currently unknown
 +	 */
 +
++	uint16_t rr_strap_xlat;
++	uint8_t rr_group_count;
 +	int i;
 +
 +	/*
@@ -6276,17 +6297,24 @@ index 0000000..ba946df
 +	if (bitentry->length < 0x5)
 +		return 0;
 +
++	if (bitentry->id[1] < 2) {
++		rr_group_count = bios->data[bitentry->offset + 2];
++		rr_strap_xlat = ROM16(bios->data[bitentry->offset + 3]);
++	} else {
++		rr_group_count = bios->data[bitentry->offset + 0];
++		rr_strap_xlat = ROM16(bios->data[bitentry->offset + 1]);
++	}
++
 +	/* adjust length of INIT_87 */
 +	for (i = 0; itbl_entry[i].name && (itbl_entry[i].id != 0x87); i++);
-+	itbl_entry[i].length += bios->data[bitentry->offset + 2] * 4;
++	itbl_entry[i].length += rr_group_count * 4;
 +
 +	/* set up multiplier for INIT_RAM_RESTRICT_ZM_REG_GROUP */
 +	for (; itbl_entry[i].name && (itbl_entry[i].id != 0x8f); i++);
-+	itbl_entry[i].length_multiplier = bios->data[bitentry->offset + 2] * 4;
++	itbl_entry[i].length_multiplier = rr_group_count * 4;
 +
 +	init_ram_restrict_zm_reg_group_blocklen = itbl_entry[i].length_multiplier;
-+
-+	bios->ram_restrict_tbl_ptr = ROM16(bios->data[bitentry->offset + 3]);
++	bios->ram_restrict_tbl_ptr = rr_strap_xlat;
 +
 +	return 0;
 +}
@@ -6377,6 +6405,14 @@ index 0000000..ba946df
 +	return 0;
 +}
 +
++static int
++parse_bit_displayport_tbl_entry(struct drm_device *dev, struct nvbios *bios,
++				struct bit_entry *bitentry)
++{
++	bios->display.dp_table_ptr = ROM16(bios->data[bitentry->offset]);
++	return 0;
++}
++
 +struct bit_table {
 +	const char id;
 +	int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *);
@@ -6435,6 +6471,7 @@ index 0000000..ba946df
 +	parse_bit_table(dev, bios, bitoffset, &BIT_TABLE('L', lvds));
 +	parse_bit_table(dev, bios, bitoffset, &BIT_TABLE('T', tmds));
 +	parse_bit_table(dev, bios, bitoffset, &BIT_TABLE('U', U));
++	parse_bit_table(dev, bios, bitoffset, &BIT_TABLE('d', displayport));
 +
 +	return 0;
 +}
@@ -6712,10 +6749,11 @@ index 0000000..ba946df
 +		 */
 +		if (port_type == 4)	/* seen on C51 */
 +			rdofs = wrofs = 1;
-+		if (port_type == 5)	/* G80+ */
++		if (port_type >= 5)	/* G80+ */
 +			rdofs = wrofs = 0;
 +	}
-+	if (dcb_i2c_ver >= 0x40 && port_type != 5)
++
++	if (dcb_i2c_ver >= 0x40 && port_type != 5 && port_type != 6)
 +		NV_WARN(dev, "DCB I2C table has port type %d\n", port_type);
 +
 +	i2c->port_type = port_type;
@@ -6725,6 +6763,204 @@ index 0000000..ba946df
 +	return 0;
 +}
 +
++static struct dcb_gpio_entry *
++new_gpio_entry(struct nvbios *bios)
++{
++	struct parsed_dcb_gpio *gpio = &bios->bdcb.gpio;
++
++	return &gpio->entry[gpio->entries++];
++}
++
++struct dcb_gpio_entry *
++nouveau_bios_gpio_entry(struct drm_device *dev, enum dcb_gpio_tag tag)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nvbios *bios = &dev_priv->VBIOS;
++	int i;
++
++	for (i = 0; i < bios->bdcb.gpio.entries; i++) {
++		if (bios->bdcb.gpio.entry[i].tag != tag)
++			continue;
++
++		return &bios->bdcb.gpio.entry[i];
++	}
++
++	return NULL;
++}
++
++static void
++parse_dcb30_gpio_entry(struct nvbios *bios, uint16_t offset)
++{
++	struct dcb_gpio_entry *gpio;
++	uint16_t ent = ROM16(bios->data[offset]);
++	uint8_t line = ent & 0x1f,
++		tag = ent >> 5 & 0x3f,
++		flags = ent >> 11 & 0x1f;
++
++	if (tag == 0x3f)
++		return;
++
++	gpio = new_gpio_entry(bios);
++
++	gpio->tag = tag;
++	gpio->line = line;
++	gpio->invert = flags != 4;
++}
++
++static void
++parse_dcb40_gpio_entry(struct nvbios *bios, uint16_t offset)
++{
++	struct dcb_gpio_entry *gpio;
++	uint32_t ent = ROM32(bios->data[offset]);
++	uint8_t line = ent & 0x1f,
++		tag = ent >> 8 & 0xff;
++
++	if (tag == 0xff)
++		return;
++
++	gpio = new_gpio_entry(bios);
++
++	/* Currently unused, we may need more fields parsed at some
++	 * point. */
++	gpio->tag = tag;
++	gpio->line = line;
++}
++
++static void
++parse_dcb_gpio_table(struct nvbios *bios)
++{
++	struct drm_device *dev = bios->dev;
++	uint16_t gpio_table_ptr = bios->bdcb.gpio_table_ptr;
++	uint8_t *gpio_table = &bios->data[gpio_table_ptr];
++	int header_len = gpio_table[1],
++	    entries = gpio_table[2],
++	    entry_len = gpio_table[3];
++	void (*parse_entry)(struct nvbios *, uint16_t) = NULL;
++	int i;
++
++	if (bios->bdcb.version >= 0x40) {
++		if (gpio_table_ptr && entry_len != 4) {
++			NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
++			return;
++		}
++
++		parse_entry = parse_dcb40_gpio_entry;
++
++	} else if (bios->bdcb.version >= 0x30) {
++		if (gpio_table_ptr && entry_len != 2) {
++			NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
++			return;
++		}
++
++		parse_entry = parse_dcb30_gpio_entry;
++
++	} else if (bios->bdcb.version >= 0x22) {
++		/*
++		 * DCBs older than v3.0 don't really have a GPIO
++		 * table, instead they keep some GPIO info at fixed
++		 * locations.
++		 */
++		uint16_t dcbptr = ROM16(bios->data[0x36]);
++		uint8_t *tvdac_gpio = &bios->data[dcbptr - 5];
++
++		if (tvdac_gpio[0] & 1) {
++			struct dcb_gpio_entry *gpio = new_gpio_entry(bios);
++
++			gpio->tag = DCB_GPIO_TVDAC0;
++			gpio->line = tvdac_gpio[1] >> 4;
++			gpio->invert = tvdac_gpio[0] & 2;
++		}
++	}
++
++	if (!gpio_table_ptr)
++		return;
++
++	if (entries > DCB_MAX_NUM_GPIO_ENTRIES) {
++		NV_WARN(dev, "Too many entries in the DCB GPIO table.\n");
++		entries = DCB_MAX_NUM_GPIO_ENTRIES;
++	}
++
++	for (i = 0; i < entries; i++)
++		parse_entry(bios, gpio_table_ptr + header_len + entry_len * i);
++}
++
++struct dcb_connector_table_entry *
++nouveau_bios_connector_entry(struct drm_device *dev, int index)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct nvbios *bios = &dev_priv->VBIOS;
++	struct dcb_connector_table_entry *cte;
++
++	if (index >= bios->bdcb.connector.entries)
++		return NULL;
++
++	cte = &bios->bdcb.connector.entry[index];
++	if (cte->type == 0xff)
++		return NULL;
++
++	return cte;
++}
++
++static void
++parse_dcb_connector_table(struct nvbios *bios)
++{
++	struct drm_device *dev = bios->dev;
++	struct dcb_connector_table *ct = &bios->bdcb.connector;
++	struct dcb_connector_table_entry *cte;
++	uint8_t *conntab = &bios->data[bios->bdcb.connector_table_ptr];
++	uint8_t *entry;
++	int i;
++
++	if (!bios->bdcb.connector_table_ptr) {
++		NV_DEBUG(dev, "No DCB connector table present\n");
++		return;
++	}
++
++	NV_INFO(dev, "DCB connector table: VHER 0x%02x %d %d %d\n",
++		conntab[0], conntab[1], conntab[2], conntab[3]);
++	if ((conntab[0] != 0x30 && conntab[0] != 0x40) ||
++	    (conntab[3] != 2 && conntab[3] != 4)) {
++		NV_ERROR(dev, "  Unknown!  Please report.\n");
++		return;
++	}
++
++	ct->entries = conntab[2];
++
++	entry = conntab + conntab[1];
++	cte = &ct->entry[0];
++	for (i = 0; i < conntab[2]; i++, entry += conntab[3], cte++) {
++		if (conntab[3] == 2)
++			cte->entry = ROM16(entry[0]);
++		else
++			cte->entry = ROM32(entry[0]);
++		cte->type  = (cte->entry & 0x000000ff) >> 0;
++		cte->index = (cte->entry & 0x00000f00) >> 8;
++		switch (cte->entry & 0x00033000) {
++		case 0x00001000:
++			cte->gpio_tag = 0x07;
++			break;
++		case 0x00002000:
++			cte->gpio_tag = 0x08;
++			break;
++		case 0x00010000:
++			cte->gpio_tag = 0x51;
++			break;
++		case 0x00020000:
++			cte->gpio_tag = 0x52;
++			break;
++		default:
++			cte->gpio_tag = 0xff;
++			break;
++		}
++
++		if (cte->type == 0xff)
++			continue;
++
++		NV_INFO(dev, "  %d: 0x%08x: type 0x%02x idx %d tag 0x%02x\n",
++			i, cte->entry, cte->type, cte->index, cte->gpio_tag);
++	}
++}
++
 +static struct dcb_entry *new_dcb_entry(struct parsed_dcb *dcb)
 +{
 +	struct dcb_entry *entry = &dcb->entry[dcb->entries];
@@ -6838,18 +7074,14 @@ index 0000000..ba946df
 +		}
 +		if (conf & mask) {
 +			/*
-+			 * I'm bored of getting this reported; left as a
-+			 * reminder for someone to fix it.
++			 * Until we even try to use these on G8x, it's
++			 * useless reporting unknown bits.  They all are.
 +			 */
-+			if (bdcb->version >= 0x40) {
-+				NV_WARN(dev, "G80+ LVDS not initialized by driver; ignoring conf bits\n");
++			if (bdcb->version >= 0x40)
 +				break;
-+			}
++
 +			NV_ERROR(dev, "Unknown LVDS configuration bits, "
-+					"please report\n");
-+			/* cause output setting to fail, so message is seen */
-+			bdcb->dcb.entries = 0;
-+			return false;
++				      "please report\n");
 +		}
 +		break;
 +		}
@@ -6862,11 +7094,29 @@ index 0000000..ba946df
 +
 +		break;
 +	}
++	case OUTPUT_DP:
++		entry->dpconf.link_bw = (conf & 0x00e00000) >> 21;
++		switch ((conf & 0x0f000000) >> 24) {
++		case 0xf:
++			entry->dpconf.link_nr = 4;
++			break;
++		case 0x3:
++			entry->dpconf.link_nr = 2;
++			break;
++		default:
++			entry->dpconf.link_nr = 1;
++			break;
++		}
++		break;
++	case OUTPUT_TMDS:
++		entry->tmdsconf.sor_link = (conf & 0x00000030) >> 4;
++		break;
 +	case 0xe:
 +		/* weird g80 mobile type that "nv" treats as a terminator */
 +		bdcb->dcb.entries--;
 +		return false;
 +	}
++
 +	/* unsure what DCB version introduces this, 3.0? */
 +	if (conf & 0x100000)
 +		entry->i2c_upper_default = true;
@@ -7054,9 +7304,8 @@ index 0000000..ba946df
 +			recordlength = dcbtable[3];
 +			i2ctabptr = ROM16(dcbtable[4]);
 +			sig = ROM32(dcbtable[6]);
-+			if (bdcb->version == 0x40)	/* G80 */
-+				bdcb->init8e_table_ptr =
-+					ROM16(dcbtable[10]);
++			bdcb->gpio_table_ptr = ROM16(dcbtable[10]);
++			bdcb->connector_table_ptr = ROM16(dcbtable[20]);
 +		} else {
 +			i2ctabptr = ROM16(dcbtable[2]);
 +			sig = ROM32(dcbtable[4]);
@@ -7121,6 +7370,9 @@ index 0000000..ba946df
 +			bdcb->i2c_default_indices = bdcb->i2c_table[4];
 +	}
 +
++	parse_dcb_gpio_table(bios);
++	parse_dcb_connector_table(bios);
++
 +	if (entries > DCB_MAX_NUM_ENTRIES)
 +		entries = DCB_MAX_NUM_ENTRIES;
 +
@@ -7327,13 +7579,16 @@ index 0000000..ba946df
 +}
 +
 +void
-+nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table)
++nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
++			    struct dcb_entry *dcbent)
 +{
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct nvbios *bios = &dev_priv->VBIOS;
 +	struct init_exec iexec = { true, false };
 +
++	bios->display.output = dcbent;
 +	parse_init_table(bios, table, &iexec);
++	bios->display.output = NULL;
 +}
 +
 +static bool NVInitVBIOS(struct drm_device *dev)
@@ -7517,10 +7772,10 @@ index 0000000..ba946df
 +}
 diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
 new file mode 100644
-index 0000000..1ffda97
+index 0000000..7cd7288
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
-@@ -0,0 +1,236 @@
+@@ -0,0 +1,280 @@
 +/*
 + * Copyright 2007-2008 Nouveau Project
 + *
@@ -7552,6 +7807,8 @@ index 0000000..1ffda97
 +
 +#define DCB_MAX_NUM_ENTRIES 16
 +#define DCB_MAX_NUM_I2C_ENTRIES 16
++#define DCB_MAX_NUM_GPIO_ENTRIES 32
++#define DCB_MAX_NUM_CONNECTOR_ENTRIES 16
 +
 +#define DCB_LOC_ON_CHIP 0
 +
@@ -7576,6 +7833,13 @@ index 0000000..1ffda97
 +		struct {
 +			bool has_component_output;
 +		} tvconf;
++		struct {
++			int link_nr;
++			int link_bw;
++		} dpconf;
++		struct {
++			int sor_link;
++		} tmdsconf;
 +	};
 +	bool i2c_upper_default;
 +};
@@ -7592,14 +7856,46 @@ index 0000000..1ffda97
 +	struct dcb_i2c_entry i2c[DCB_MAX_NUM_I2C_ENTRIES];
 +};
 +
++enum dcb_gpio_tag {
++	DCB_GPIO_TVDAC0 = 0xc,
++	DCB_GPIO_TVDAC1 = 0x2d,
++};
++
++struct dcb_gpio_entry {
++	enum dcb_gpio_tag tag;
++	int line;
++	bool invert;
++};
++
++struct parsed_dcb_gpio {
++	int entries;
++	struct dcb_gpio_entry entry[DCB_MAX_NUM_GPIO_ENTRIES];
++};
++
++struct dcb_connector_table_entry {
++	uint32_t entry;
++	uint8_t type;
++	uint8_t index;
++	uint8_t gpio_tag;
++};
++
++struct dcb_connector_table {
++	int entries;
++	struct dcb_connector_table_entry entry[DCB_MAX_NUM_CONNECTOR_ENTRIES];
++};
++
 +struct bios_parsed_dcb {
 +	uint8_t version;
 +
 +	struct parsed_dcb dcb;
 +
-+	uint16_t init8e_table_ptr;
 +	uint8_t *i2c_table;
 +	uint8_t i2c_default_indices;
++
++	uint16_t gpio_table_ptr;
++	struct parsed_dcb_gpio gpio;
++	uint16_t connector_table_ptr;
++	struct dcb_connector_table connector;
 +};
 +
 +enum nouveau_encoder_type {
@@ -7715,6 +8011,7 @@ index 0000000..1ffda97
 +	struct {
 +		struct dcb_entry *output;
 +		uint16_t script_table_ptr;
++		uint16_t dp_table_ptr;
 +	} display;
 +
 +	struct {
@@ -7730,7 +8027,9 @@ index 0000000..1ffda97
 +		bool dual_link;
 +		bool link_c_increment;
 +		bool BITbit1;
++		bool if_is_24bit;
 +		int duallink_transition_clk;
++		uint8_t strapless_is_24bit;
 +		uint8_t *edid;
 +
 +		/* will need resetting after suspend */
@@ -8428,10 +8727,10 @@ index 0000000..8d1383a
 +
 diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c
 new file mode 100644
-index 0000000..3f80db8
+index 0000000..81271d6
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_calc.c
-@@ -0,0 +1,626 @@
+@@ -0,0 +1,469 @@
 +/*
 + * Copyright 1993-2003 NVIDIA, Corporation
 + * Copyright 2007-2009 Stuart Bennett
@@ -8468,35 +8767,31 @@ index 0000000..3f80db8
 +\****************************************************************************/
 +
 +struct nv_fifo_info {
-+	int graphics_lwm;
-+	int video_lwm;
-+	int graphics_burst_size;
-+	int video_burst_size;
-+	bool valid;
++	int lwm;
++	int burst;
 +};
 +
 +struct nv_sim_state {
 +	int pclk_khz;
 +	int mclk_khz;
 +	int nvclk_khz;
-+	int pix_bpp;
-+	bool enable_mp;
-+	bool enable_video;
++	int bpp;
 +	int mem_page_miss;
 +	int mem_latency;
 +	int memory_type;
 +	int memory_width;
++	int two_heads;
 +};
 +
 +static void
-+nv4CalcArbitration(struct nv_fifo_info *fifo, struct nv_sim_state *arb)
++nv04_calc_arb(struct nv_fifo_info *fifo, struct nv_sim_state *arb)
 +{
-+	int pagemiss, cas, width, video_enable, bpp;
-+	int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
++	int pagemiss, cas, width, bpp;
++	int nvclks, mclks, pclks, crtpagemiss;
 +	int found, mclk_extra, mclk_loop, cbs, m1, p1;
-+	int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
-+	int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
-+	int vpm_us, us_video, vlwm, video_fill_us, cpm_us, us_crt, clwm;
++	int mclk_freq, pclk_freq, nvclk_freq;
++	int us_m, us_n, us_p, crtc_drain_rate;
++	int cpm_us, us_crt, clwm;
 +
 +	pclk_freq = arb->pclk_khz;
 +	mclk_freq = arb->mclk_khz;
@@ -8504,277 +8799,134 @@ index 0000000..3f80db8
 +	pagemiss = arb->mem_page_miss;
 +	cas = arb->mem_latency;
 +	width = arb->memory_width >> 6;
-+	video_enable = arb->enable_video;
-+	bpp = arb->pix_bpp;
-+	mp_enable = arb->enable_mp;
-+	clwm = 0;
-+	vlwm = 0;
++	bpp = arb->bpp;
 +	cbs = 128;
++
 +	pclks = 2;
-+	nvclks = 2;
-+	nvclks += 2;
-+	nvclks += 1;
-+	mclks = 5;
-+	mclks += 3;
-+	mclks += 1;
-+	mclks += cas;
-+	mclks += 1;
-+	mclks += 1;
-+	mclks += 1;
-+	mclks += 1;
++	nvclks = 10;
++	mclks = 13 + cas;
 +	mclk_extra = 3;
-+	nvclks += 2;
-+	nvclks += 1;
-+	nvclks += 1;
-+	nvclks += 1;
-+	if (mp_enable)
-+		mclks += 4;
-+	nvclks += 0;
-+	pclks += 0;
 +	found = 0;
-+	vbs = 0;
-+	while (found != 1) {
-+		fifo->valid = true;
++
++	while (!found) {
 +		found = 1;
++
 +		mclk_loop = mclks + mclk_extra;
 +		us_m = mclk_loop * 1000 * 1000 / mclk_freq;
 +		us_n = nvclks * 1000 * 1000 / nvclk_freq;
 +		us_p = nvclks * 1000 * 1000 / pclk_freq;
-+		if (video_enable) {
-+			video_drain_rate = pclk_freq * 2;
-+			crtc_drain_rate = pclk_freq * bpp / 8;
-+			vpagemiss = 2;
-+			vpagemiss += 1;
-+			crtpagemiss = 2;
-+			vpm_us = vpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
-+			if (nvclk_freq * 2 > mclk_freq * width)
-+				video_fill_us = cbs * 1000 * 1000 / 16 / nvclk_freq;
-+			else
-+				video_fill_us = cbs * 1000 * 1000 / (8 * width) / mclk_freq;
-+			us_video = vpm_us + us_m + us_n + us_p + video_fill_us;
-+			vlwm = us_video * video_drain_rate / (1000 * 1000);
-+			vlwm++;
-+			vbs = 128;
-+			if (vlwm > 128)
-+				vbs = 64;
-+			if (vlwm > (256 - 64))
-+				vbs = 32;
-+			if (nvclk_freq * 2 > mclk_freq * width)
-+				video_fill_us = vbs * 1000 * 1000 / 16 / nvclk_freq;
-+			else
-+				video_fill_us = vbs * 1000 * 1000 / (8 * width) / mclk_freq;
-+			cpm_us = crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
-+			us_crt = us_video + video_fill_us + cpm_us + us_m + us_n + us_p;
-+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
-+			clwm++;
-+		} else {
-+			crtc_drain_rate = pclk_freq * bpp / 8;
-+			crtpagemiss = 2;
-+			crtpagemiss += 1;
-+			cpm_us = crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
-+			us_crt = cpm_us + us_m + us_n + us_p;
-+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
-+			clwm++;
-+		}
++
++		crtc_drain_rate = pclk_freq * bpp / 8;
++		crtpagemiss = 2;
++		crtpagemiss += 1;
++		cpm_us = crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
++		us_crt = cpm_us + us_m + us_n + us_p;
++		clwm = us_crt * crtc_drain_rate / (1000 * 1000);
++		clwm++;
++
 +		m1 = clwm + cbs - 512;
 +		p1 = m1 * pclk_freq / mclk_freq;
 +		p1 = p1 * bpp / 8;
-+		if ((p1 < m1 && m1 > 0) ||
-+		    (video_enable && (clwm > 511 || vlwm > 255)) ||
-+		    (!video_enable && clwm > 519)) {
-+			fifo->valid = false;
++		if ((p1 < m1 && m1 > 0) || clwm > 519) {
 +			found = !mclk_extra;
 +			mclk_extra--;
 +		}
 +		if (clwm < 384)
 +			clwm = 384;
-+		if (vlwm < 128)
-+			vlwm = 128;
-+		fifo->graphics_lwm = clwm;
-+		fifo->graphics_burst_size = 128;
-+		fifo->video_lwm = vlwm + 15;
-+		fifo->video_burst_size = vbs;
++
++		fifo->lwm = clwm;
++		fifo->burst = cbs;
 +	}
 +}
 +
 +static void
-+nv10CalcArbitration(struct nv_fifo_info *fifo, struct nv_sim_state *arb)
-+{
-+	int pagemiss, width, video_enable, bpp;
-+	int nvclks, mclks, pclks, vpagemiss, crtpagemiss;
-+	int nvclk_fill;
-+	int found, mclk_extra, mclk_loop, cbs, m1;
-+	int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
-+	int us_m, us_m_min, us_n, us_p, crtc_drain_rate;
-+	int vus_m;
-+	int vpm_us, us_video, cpm_us, us_crt, clwm;
-+	int clwm_rnd_down, min_clwm;
-+	int m2us, us_pipe_min, p1clk, p2;
-+	int min_mclk_extra;
-+	int us_min_mclk_extra;
++nv10_calc_arb(struct nv_fifo_info *fifo, struct nv_sim_state *arb)
++{
++	int fill_rate, drain_rate;
++	int pclks, nvclks, mclks, xclks;
++	int pclk_freq, nvclk_freq, mclk_freq;
++	int fill_lat, extra_lat;
++	int max_burst_o, max_burst_l;
++	int fifo_len, min_lwm, max_lwm;
++	const int burst_lat = 80; /* Maximum allowable latency due
++				   * to the CRTC FIFO burst. (ns) */
 +
-+	pclk_freq = arb->pclk_khz;	/* freq in KHz */
-+	mclk_freq = arb->mclk_khz;
++	pclk_freq = arb->pclk_khz;
 +	nvclk_freq = arb->nvclk_khz;
-+	pagemiss = arb->mem_page_miss;
-+	width = arb->memory_width / 64;
-+	video_enable = arb->enable_video;
-+	bpp = arb->pix_bpp;
-+	mp_enable = arb->enable_mp;
-+	clwm = 0;
-+	cbs = 512;
-+	pclks = 4;	/* lwm detect. */
-+	nvclks = 3;	/* lwm -> sync. */
-+	nvclks += 2;	/* fbi bus cycles (1 req + 1 busy) */
-+	mclks = 1;	/* 2 edge sync.  may be very close to edge so just put one. */
-+	mclks += 1;	/* arb_hp_req */
-+	mclks += 5;	/* ap_hp_req   tiling pipeline */
-+	mclks += 2;	/* tc_req     latency fifo */
-+	mclks += 2;	/* fb_cas_n_  memory request to fbio block */
-+	mclks += 7;	/* sm_d_rdv   data returned from fbio block */
-+
-+	/* fb.rd.d.Put_gc   need to accumulate 256 bits for read */
-+	if (arb->memory_type == 0) {
-+		if (arb->memory_width == 64)	/* 64 bit bus */
-+			mclks += 4;
-+		else
-+			mclks += 2;
-+	} else if (arb->memory_width == 64)	/* 64 bit bus */
-+		mclks += 2;
-+	else
-+		mclks += 1;
++	mclk_freq = arb->mclk_khz;
 +
-+	if (!video_enable && arb->memory_width == 128) {
-+		mclk_extra = (bpp == 32) ? 31 : 42;	/* Margin of error */
-+		min_mclk_extra = 17;
-+	} else {
-+		mclk_extra = (bpp == 32) ? 8 : 4;	/* Margin of error */
-+		/* mclk_extra = 4; *//* Margin of error */
-+		min_mclk_extra = 18;
-+	}
-+
-+	nvclks += 1;	/* 2 edge sync.  may be very close to edge so just put one. */
-+	nvclks += 1;	/* fbi_d_rdv_n */
-+	nvclks += 1;	/* Fbi_d_rdata */
-+	nvclks += 1;	/* crtfifo load */
-+
-+	if (mp_enable)
-+		mclks += 4;	/* Mp can get in with a burst of 8. */
-+	/* Extra clocks determined by heuristics */
++	fill_rate = mclk_freq * arb->memory_width / 8; /* kB/s */
++	drain_rate = pclk_freq * arb->bpp / 8; /* kB/s */
 +
-+	nvclks += 0;
-+	pclks += 0;
-+	found = 0;
-+	while (found != 1) {
-+		fifo->valid = true;
-+		found = 1;
-+		mclk_loop = mclks + mclk_extra;
-+		us_m = mclk_loop * 1000 * 1000 / mclk_freq;	/* Mclk latency in us */
-+		us_m_min = mclks * 1000 * 1000 / mclk_freq;	/* Minimum Mclk latency in us */
-+		us_min_mclk_extra = min_mclk_extra * 1000 * 1000 / mclk_freq;
-+		us_n = nvclks * 1000 * 1000 / nvclk_freq;	/* nvclk latency in us */
-+		us_p = pclks * 1000 * 1000 / pclk_freq;	/* nvclk latency in us */
-+		us_pipe_min = us_m_min + us_n + us_p;
++	fifo_len = arb->two_heads ? 1536 : 1024; /* B */
 +
-+		vus_m = mclk_loop * 1000 * 1000 / mclk_freq;	/* Mclk latency in us */
++	/* Fixed FIFO refill latency. */
 +
-+		if (video_enable) {
-+			crtc_drain_rate = pclk_freq * bpp / 8;	/* MB/s */
++	pclks = 4;	/* lwm detect. */
 +
-+			vpagemiss = 1;	/* self generating page miss */
-+			vpagemiss += 1;	/* One higher priority before */
++	nvclks = 3	/* lwm -> sync. */
++		+ 2	/* fbi bus cycles (1 req + 1 busy) */
++		+ 1	/* 2 edge sync.  may be very close to edge so
++			 * just put one. */
++		+ 1	/* fbi_d_rdv_n */
++		+ 1	/* Fbi_d_rdata */
++		+ 1;	/* crtfifo load */
 +
-+			crtpagemiss = 2;	/* self generating page miss */
-+			if (mp_enable)
-+				crtpagemiss += 1;	/* if MA0 conflict */
++	mclks = 1	/* 2 edge sync.  may be very close to edge so
++			 * just put one. */
++		+ 1	/* arb_hp_req */
++		+ 5	/* tiling pipeline */
++		+ 2	/* latency fifo */
++		+ 2	/* memory request to fbio block */
++		+ 7;	/* data returned from fbio block */
 +
-+			vpm_us = vpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
++	/* Need to accumulate 256 bits for read */
++	mclks += (arb->memory_type == 0 ? 2 : 1)
++		* arb->memory_width / 32;
 +
-+			us_video = vpm_us + vus_m;	/* Video has separate read return path */
++	fill_lat = mclks * 1000 * 1000 / mclk_freq   /* minimum mclk latency */
++		+ nvclks * 1000 * 1000 / nvclk_freq  /* nvclk latency */
++		+ pclks * 1000 * 1000 / pclk_freq;   /* pclk latency */
 +
-+			cpm_us = crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
-+			us_crt = us_video	/* Wait for video */
-+				 + cpm_us	/* CRT Page miss */
-+				 + us_m + us_n + us_p;	/* other latency */
++	/* Conditional FIFO refill latency. */
 +
-+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
-+			clwm++;	/* fixed point <= float_point - 1.  Fixes that */
-+		} else {
-+			crtc_drain_rate = pclk_freq * bpp / 8;	/* bpp * pclk/8 */
++	xclks = 2 * arb->mem_page_miss + mclks /* Extra latency due to
++						* the overlay. */
++		+ 2 * arb->mem_page_miss       /* Extra pagemiss latency. */
++		+ (arb->bpp == 32 ? 8 : 4);    /* Margin of error. */
 +
-+			crtpagemiss = 1;	/* self generating page miss */
-+			crtpagemiss += 1;	/* MA0 page miss */
-+			if (mp_enable)
-+				crtpagemiss += 1;	/* if MA0 conflict */
-+			cpm_us = crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq;
-+			us_crt = cpm_us + us_m + us_n + us_p;
-+			clwm = us_crt * crtc_drain_rate / (1000 * 1000);
-+			clwm++;	/* fixed point <= float_point - 1.  Fixes that */
-+
-+			/* Finally, a heuristic check when width == 64 bits */
-+			if (width == 1) {
-+				nvclk_fill = nvclk_freq * 8;
-+				if (crtc_drain_rate * 100 >= nvclk_fill * 102)
-+					clwm = 0xfff;	/* Large number to fail */
-+				else if (crtc_drain_rate * 100 >= nvclk_fill * 98) {
-+					clwm = 1024;
-+					cbs = 512;
-+				}
-+			}
-+		}
++	extra_lat = xclks * 1000 * 1000 / mclk_freq;
 +
-+		/*
-+		 * Overfill check:
-+		 */
++	if (arb->two_heads)
++		/* Account for another CRTC. */
++		extra_lat += fill_lat + extra_lat + burst_lat;
 +
-+		clwm_rnd_down = (clwm / 8) * 8;
-+		if (clwm_rnd_down < clwm)
-+			clwm += 8;
-+
-+		m1 = clwm + cbs - 1024;	/* Amount of overfill */
-+		m2us = us_pipe_min + us_min_mclk_extra;
-+
-+		/* pclk cycles to drain */
-+		p1clk = m2us * pclk_freq / (1000 * 1000);
-+		p2 = p1clk * bpp / 8;	/* bytes drained. */
-+
-+		if (p2 < m1 && m1 > 0) {
-+			fifo->valid = false;
-+			found = 0;
-+			if (min_mclk_extra == 0) {
-+				if (cbs <= 32)
-+					found = 1;	/* Can't adjust anymore! */
-+				else
-+					cbs = cbs / 2;	/* reduce the burst size */
-+			} else
-+				min_mclk_extra--;
-+		} else if (clwm > 1023) {	/* Have some margin */
-+			fifo->valid = false;
-+			found = 0;
-+			if (min_mclk_extra == 0)
-+				found = 1;	/* Can't adjust anymore! */
-+			else
-+				min_mclk_extra--;
-+		}
++	/* FIFO burst */
 +
-+		/* This correction works around a slight snow effect
-+		 * when the TV and VGA outputs are enabled simultaneously. */
-+		min_clwm = 1024 - cbs + 128 * pclk_freq / 100000;
-+		if (clwm < min_clwm)
-+			clwm = min_clwm;
++	/* Max burst not leading to overflows. */
++	max_burst_o = (1 + fifo_len - extra_lat * drain_rate / (1000 * 1000))
++		* (fill_rate / 1000) / ((fill_rate - drain_rate) / 1000);
++	fifo->burst = min(max_burst_o, 1024);
 +
-+		/*  printf("CRT LWM: prog: 0x%x, bs: 256\n", clwm); */
-+		fifo->graphics_lwm = clwm;
-+		fifo->graphics_burst_size = cbs;
++	/* Max burst value with an acceptable latency. */
++	max_burst_l = burst_lat * fill_rate / (1000 * 1000);
++	fifo->burst = min(max_burst_l, fifo->burst);
 +
-+		fifo->video_lwm = 1024;
-+		fifo->video_burst_size = 512;
-+	}
++	fifo->burst = rounddown_pow_of_two(fifo->burst);
++
++	/* FIFO low watermark */
++
++	min_lwm = (fill_lat + extra_lat) * drain_rate / (1000 * 1000) + 1;
++	max_lwm = fifo_len - fifo->burst
++		+ fill_lat * drain_rate / (1000 * 1000)
++		+ fifo->burst * drain_rate / fill_rate;
++
++	fifo->lwm = min_lwm + 10 * (max_lwm - min_lwm) / 100; /* Empirical. */
 +}
 +
 +static void
-+nv4_10UpdateArbitrationSettings(struct drm_device *dev, int VClk, int bpp,
-+				int *burst, int *lwm)
++nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
++		int *burst, int *lwm)
 +{
 +	struct nv_fifo_info fifo_data;
 +	struct nv_sim_state sim_data;
@@ -8785,21 +8937,19 @@ index 0000000..3f80db8
 +	sim_data.pclk_khz = VClk;
 +	sim_data.mclk_khz = MClk;
 +	sim_data.nvclk_khz = NVClk;
-+	sim_data.pix_bpp = bpp;
-+	sim_data.enable_mp = false;
++	sim_data.bpp = bpp;
++	sim_data.two_heads = nv_two_heads(dev);
 +	if ((dev->pci_device & 0xffff) == 0x01a0 /*CHIPSET_NFORCE*/ ||
 +	    (dev->pci_device & 0xffff) == 0x01f0 /*CHIPSET_NFORCE2*/) {
 +		uint32_t type;
 +
 +		pci_read_config_dword(pci_get_bus_and_slot(0, 1), 0x7c, &type);
 +
-+		sim_data.enable_video = false;
 +		sim_data.memory_type = (type >> 12) & 1;
 +		sim_data.memory_width = 64;
 +		sim_data.mem_latency = 3;
 +		sim_data.mem_page_miss = 10;
 +	} else {
-+		sim_data.enable_video = (nv_arch(dev) != NV_04);
 +		sim_data.memory_type = nvReadFB(dev, NV_PFB_CFG0) & 0x1;
 +		sim_data.memory_width = (nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64;
 +		sim_data.mem_latency = cfg1 & 0xf;
@@ -8807,21 +8957,16 @@ index 0000000..3f80db8
 +	}
 +
 +	if (nv_arch(dev) == NV_04)
-+		nv4CalcArbitration(&fifo_data, &sim_data);
++		nv04_calc_arb(&fifo_data, &sim_data);
 +	else
-+		nv10CalcArbitration(&fifo_data, &sim_data);
++		nv10_calc_arb(&fifo_data, &sim_data);
 +
-+	if (fifo_data.valid) {
-+		int b = fifo_data.graphics_burst_size >> 4;
-+		*burst = 0;
-+		while (b >>= 1)
-+			(*burst)++;
-+		*lwm = fifo_data.graphics_lwm >> 3;
-+	}
++	*burst = ilog2(fifo_data.burst >> 4);
++	*lwm = fifo_data.lwm >> 3;
 +}
 +
 +static void
-+nv30UpdateArbitrationSettings(int *burst, int *lwm)
++nv30_update_arb(int *burst, int *lwm)
 +{
 +	unsigned int fifo_size, burst_size, graphics_lwm;
 +
@@ -8829,10 +8974,7 @@ index 0000000..3f80db8
 +	burst_size = 512;
 +	graphics_lwm = fifo_size - burst_size;
 +
-+	*burst = 0;
-+	burst_size >>= 5;
-+	while (burst_size >>= 1)
-+		(*burst)++;
++	*burst = ilog2(burst_size >> 5);
 +	*lwm = graphics_lwm >> 3;
 +}
 +
@@ -8840,13 +8982,13 @@ index 0000000..3f80db8
 +nouveau_calc_arb(struct drm_device *dev, int vclk, int bpp, int *burst, int *lwm)
 +{
 +	if (nv_arch(dev) < NV_30)
-+		nv4_10UpdateArbitrationSettings(dev, vclk, bpp, burst, lwm);
++		nv04_update_arb(dev, vclk, bpp, burst, lwm);
 +	else if ((dev->pci_device & 0xfff0) == 0x0240 /*CHIPSET_C51*/ ||
 +		 (dev->pci_device & 0xfff0) == 0x03d0 /*CHIPSET_C512*/) {
 +		*burst = 128;
 +		*lwm = 0x0480;
 +	} else
-+		nv30UpdateArbitrationSettings(burst, lwm);
++		nv30_update_arb(burst, lwm);
 +}
 +
 +static int
@@ -9534,10 +9676,10 @@ index 0000000..9aaa972
 +int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);
 diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
 new file mode 100644
-index 0000000..1e40ef0
+index 0000000..06d6d73
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
-@@ -0,0 +1,811 @@
+@@ -0,0 +1,812 @@
 +/*
 + * Copyright (C) 2008 Maarten Maathuis.
 + * All Rights Reserved.
@@ -10203,9 +10345,9 @@ index 0000000..1e40ef0
 +	 * modeline is avalilable for the panel, set it as the panel's
 +	 * native mode and exit.
 +	 */
-+	if (!nv_connector->edid &&
-+	     nv_encoder->dcb->lvdsconf.use_straps_for_mode &&
-+	     nouveau_bios_fp_mode(dev, &native)) {
++	if (!nv_connector->edid && nouveau_bios_fp_mode(dev, &native) &&
++	     (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
++	      dev_priv->VBIOS.pub.fp_no_ddc)) {
 +		nv_connector->native_mode = drm_mode_duplicate(dev, &native);
 +		goto out;
 +	}
@@ -10258,6 +10400,7 @@ index 0000000..1e40ef0
 +	nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
 +	if (!nv_connector)
 +		return -ENOMEM;
++	nv_connector->dcb = nouveau_bios_connector_entry(dev, index);
 +	connector = &nv_connector->base;
 +
 +	switch (type) {
@@ -10351,10 +10494,10 @@ index 0000000..1e40ef0
 +}
 diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
 new file mode 100644
-index 0000000..75dbe9b
+index 0000000..728b809
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
-@@ -0,0 +1,55 @@
+@@ -0,0 +1,54 @@
 +/*
 + * Copyright (C) 2008 Maarten Maathuis.
 + * All Rights Reserved.
@@ -10390,15 +10533,14 @@ index 0000000..75dbe9b
 +struct nouveau_connector {
 +	struct drm_connector base;
 +
-+	struct drm_display_mode *native_mode;
++	struct dcb_connector_table_entry *dcb;
 +
 +	int scaling_mode;
-+
 +	bool use_dithering;
 +
 +	struct nouveau_encoder *detected_encoder;
-+
 +	struct edid *edid;
++	struct drm_display_mode *native_mode;
 +};
 +
 +static inline struct nouveau_connector *nouveau_connector(
@@ -11589,10 +11731,10 @@ index 0000000..d8de3f6
 +MODULE_LICENSE("GPL and additional rights");
 diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
 new file mode 100644
-index 0000000..d16c843
+index 0000000..a4ab9d1
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
-@@ -0,0 +1,1288 @@
+@@ -0,0 +1,1299 @@
 +/*
 + * Copyright 2005 Stephane Marchesin.
 + * All Rights Reserved.
@@ -12081,7 +12223,9 @@ index 0000000..d16c843
 +	void __iomem *ramin;
 +	uint32_t ramin_size;
 +
++	struct workqueue_struct *wq;
 +	struct work_struct irq_work;
++
 +	struct list_head vbl_waiting;
 +
 +	struct {
@@ -12429,7 +12573,12 @@ index 0000000..d16c843
 +extern int nouveau_bios_init(struct drm_device *);
 +extern void nouveau_bios_takedown(struct drm_device *dev);
 +extern int nouveau_run_vbios_init(struct drm_device *);
-+extern void nouveau_bios_run_init_table(struct drm_device *, uint16_t table);
++extern void nouveau_bios_run_init_table(struct drm_device *, uint16_t table,
++					struct dcb_entry *);
++extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *,
++						      enum dcb_gpio_tag);
++extern struct dcb_connector_table_entry *
++nouveau_bios_connector_entry(struct drm_device *, int index);
 +extern int get_pll_limits(struct drm_device *, uint32_t limit_match,
 +			  struct pll_lims *);
 +extern int nouveau_bios_run_display_table(struct drm_device *,
@@ -12690,6 +12839,10 @@ index 0000000..d16c843
 +extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
 +				  struct drm_file *);
 +
++/* nv17_gpio.c */
++int nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
++int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
++
 +#ifndef ioread32_native
 +#ifdef __BIG_ENDIAN
 +#define ioread16_native ioread16be
@@ -13715,10 +13868,10 @@ index 0000000..0cff7eb
 +
 diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
 new file mode 100644
-index 0000000..b8c3664
+index 0000000..f10b53b
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
-@@ -0,0 +1,981 @@
+@@ -0,0 +1,976 @@
 +/*
 + * Copyright (C) 2008 Ben Skeggs.
 + * All Rights Reserved.
@@ -13825,7 +13978,7 @@ index 0000000..b8c3664
 +}
 +
 +static bool
-+nouveau_gem_tile_mode_valid(struct drm_device *dev, uint32_t tile_flags) {
++nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) {
 +	switch (tile_flags) {
 +	case 0x0000:
 +	case 0x1800:
@@ -13872,12 +14025,7 @@ index 0000000..b8c3664
 +	if (!flags || req->info.domain & NOUVEAU_GEM_DOMAIN_CPU)
 +		flags |= TTM_PL_FLAG_SYSTEM;
 +
-+	if (req->info.tile_mode > 4) {
-+		NV_ERROR(dev, "bad tile mode: %d\n", req->info.tile_mode);
-+		return -EINVAL;
-+	}
-+
-+	if (!nouveau_gem_tile_mode_valid(dev, req->info.tile_flags))
++	if (!nouveau_gem_tile_flags_valid(dev, req->info.tile_flags))
 +		return -EINVAL;
 +
 +	ret = nouveau_gem_new(dev, chan, req->info.size, req->align, flags,
@@ -20548,10 +20696,10 @@ index 0000000..4c7f1e4
 +}
 diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
 new file mode 100644
-index 0000000..790630d
+index 0000000..205b6d9
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nouveau_state.c
-@@ -0,0 +1,872 @@
+@@ -0,0 +1,876 @@
 +/*
 + * Copyright 2005 Stephane Marchesin
 + * Copyright 2008 Stuart Bennett
@@ -21139,6 +21287,10 @@ index 0000000..790630d
 +	if (dev_priv->acpi_dsm)
 +		nouveau_hybrid_setup(dev);
 +
++	dev_priv->wq = create_workqueue("nouveau");
++	if (!dev_priv->wq)
++		return -EINVAL;
++
 +	/* resource 0 is mmio regs */
 +	/* resource 1 is linear FB */
 +	/* resource 2 is RAMIN (mmio regs + 0x1000000) */
@@ -21563,10 +21715,10 @@ index 0000000..7818981
 +
 diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
 new file mode 100644
-index 0000000..2ab9f30
+index 0000000..0a5cfc1
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
-@@ -0,0 +1,992 @@
+@@ -0,0 +1,1001 @@
 +/*
 + * Copyright 1993-2003 NVIDIA, Corporation
 + * Copyright 2006 Dave Airlie
@@ -21675,10 +21827,8 @@ index 0000000..2ab9f30
 +	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 +	struct nv04_mode_state *state = &dev_priv->mode_reg;
 +	struct nv04_crtc_reg *regp = &state->crtc_reg[nv_crtc->index];
-+	struct drm_framebuffer *fb = crtc->fb;
 +	struct nouveau_pll_vals *pv = &regp->pllvals;
 +	struct pll_lims pll_lim;
-+	int vclk, arb_burst, arb_fifo_lwm;
 +
 +	if (get_pll_limits(dev, nv_crtc->index ? VPLL2 : VPLL1, &pll_lim))
 +		return;
@@ -21699,8 +21849,7 @@ index 0000000..2ab9f30
 +	if (dev_priv->chipset > 0x40 && dot_clock <= (pll_lim.vco1.maxfreq / 2))
 +		memset(&pll_lim.vco2, 0, sizeof(pll_lim.vco2));
 +
-+	vclk = nouveau_calc_pll_mnp(dev, &pll_lim, dot_clock, pv);
-+	if (!vclk)
++	if (!nouveau_calc_pll_mnp(dev, &pll_lim, dot_clock, pv))
 +		return;
 +
 +	state->pllsel &= PLLSEL_VPLL1_MASK | PLLSEL_VPLL2_MASK | PLLSEL_TV_MASK;
@@ -21721,13 +21870,6 @@ index 0000000..2ab9f30
 +		NV_TRACE(dev, "vpll: n %d m %d log2p %d\n",
 +			 pv->N1, pv->M1, pv->log2P);
 +
-+	nouveau_calc_arb(dev, vclk, fb->bits_per_pixel, &arb_burst, &arb_fifo_lwm);
-+
-+	regp->CRTC[NV_CIO_CRE_FF_INDEX] = arb_burst;
-+	regp->CRTC[NV_CIO_CRE_FFLWM__INDEX] = arb_fifo_lwm & 0xff;
-+	if (nv_arch(dev) >= NV_30)
-+		regp->CRTC[NV_CIO_CRE_47] = arb_fifo_lwm >> 8;
-+
 +	nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset);
 +}
 +
@@ -22344,10 +22486,12 @@ index 0000000..2ab9f30
 +			struct drm_framebuffer *old_fb)
 +{
 +	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-+	struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
++	struct drm_device *dev = crtc->dev;
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
 +	struct drm_framebuffer *drm_fb = nv_crtc->base.fb;
 +	struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
++	int arb_burst, arb_lwm;
 +	int ret;
 +
 +	ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
@@ -22366,13 +22510,14 @@ index 0000000..2ab9f30
 +		nv_crtc_gamma_load(crtc);
 +	}
 +
++	/* Update the framebuffer format. */
 +	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] &= ~3;
 +	regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->fb->depth + 1) / 8;
 +	regp->ramdac_gen_ctrl &= ~NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
 +	if (crtc->fb->depth == 16)
 +		regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
 +	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_PIXEL_INDEX);
-+	NVWriteRAMDAC(crtc->dev, nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL,
++	NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL,
 +		      regp->ramdac_gen_ctrl);
 +
 +	regp->CRTC[NV_CIO_CR_OFFSET_INDEX] = drm_fb->pitch >> 3;
@@ -22381,9 +22526,25 @@ index 0000000..2ab9f30
 +	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_RPC0_INDEX);
 +	crtc_wr_cio_state(crtc, regp, NV_CIO_CR_OFFSET_INDEX);
 +
++	/* Update the framebuffer location. */
 +	regp->fb_start = nv_crtc->fb.offset & ~3;
 +	regp->fb_start += (y * drm_fb->pitch) + (x * drm_fb->bits_per_pixel / 8);
-+	NVWriteCRTC(crtc->dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start);
++	NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start);
++
++	/* Update the arbitration parameters. */
++	nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel,
++			 &arb_burst, &arb_lwm);
++
++	regp->CRTC[NV_CIO_CRE_FF_INDEX] = arb_burst;
++	regp->CRTC[NV_CIO_CRE_FFLWM__INDEX] = arb_lwm & 0xff;
++	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FF_INDEX);
++	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FFLWM__INDEX);
++
++	if (nv_arch(dev) >= NV_30) {
++		regp->CRTC[NV_CIO_CRE_47] = arb_lwm >> 8;
++		crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_47);
++	}
++
 +	return 0;
 +}
 +
@@ -22637,10 +22798,10 @@ index 0000000..fc9156e
 +
 diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
 new file mode 100644
-index 0000000..587b6f5
+index 0000000..f781761
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv04_dac.c
-@@ -0,0 +1,529 @@
+@@ -0,0 +1,528 @@
 +/*
 + * Copyright 2003 NVIDIA, Corporation
 + * Copyright 2006 Dave Airlie
@@ -22863,7 +23024,7 @@ index 0000000..587b6f5
 +	struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
 +	uint32_t testval, regoffset = nv04_dac_output_offset(encoder);
 +	uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput,
-+		saved_rtest_ctrl, temp, saved_gpio_ext = 0, routput;
++		saved_rtest_ctrl, saved_gpio0, saved_gpio1, temp, routput;
 +	int head, present = 0;
 +
 +#define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20)
@@ -22891,12 +23052,11 @@ index 0000000..587b6f5
 +		nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf);
 +	}
 +
-+	if (dev_priv->chipset >= 0x34) {
-+		saved_gpio_ext = NVReadCRTC(dev, 0, NV_PCRTC_GPIO_EXT);
++	saved_gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1);
++	saved_gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0);
 +
-+		NVWriteCRTC(dev, 0, NV_PCRTC_GPIO_EXT, (saved_gpio_ext & ~(3 << 20)) |
-+			    (dcb->type == OUTPUT_TV ? (1 << 20) : 0));
-+	}
++	nv17_gpio_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV);
++	nv17_gpio_set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV);
 +
 +	msleep(4);
 +
@@ -22913,9 +23073,9 @@ index 0000000..587b6f5
 +
 +	if (nv_arch(dev) >= NV_40) {
 +		if (dcb->type == OUTPUT_TV)
-+			routput |= 1 << 20;
++			routput |= 0x1a << 16;
 +		else
-+			routput &= ~(1 << 20);
++			routput &= ~(0x1a << 16);
 +	}
 +
 +	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, routput);
@@ -22934,7 +23094,7 @@ index 0000000..587b6f5
 +	temp = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
 +
 +	if (dcb->type == OUTPUT_TV)
-+		present = (nv17_tv_detect(encoder, connector, (temp >> 28) & 0xe)
++		present = (nv17_tv_detect(encoder, connector, temp)
 +			   == connector_status_connected);
 +	else
 +		present = temp & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI;
@@ -22951,8 +23111,8 @@ index 0000000..587b6f5
 +		nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4);
 +	nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2);
 +
-+	if (dev_priv->chipset >= 0x34)
-+		NVWriteRAMDAC(dev, 0, NV_PCRTC_GPIO_EXT, saved_gpio_ext);
++	nv17_gpio_set(dev, DCB_GPIO_TVDAC1, saved_gpio1);
++	nv17_gpio_set(dev, DCB_GPIO_TVDAC0, saved_gpio0);
 +
 +	if (present) {
 +		NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or));
@@ -27111,12 +27271,110 @@ index 0000000..6bf6804
 +	{ 0x0099, false, NULL }, /* celcius (nv17) */
 +	{}
 +};
+diff --git a/drivers/gpu/drm/nouveau/nv17_gpio.c b/drivers/gpu/drm/nouveau/nv17_gpio.c
+new file mode 100644
+index 0000000..2e58c33
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nv17_gpio.c
+@@ -0,0 +1,92 @@
++/*
++ * Copyright (C) 2009 Francisco Jerez.
++ * All Rights Reserved.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining
++ * a copy of this software and associated documentation files (the
++ * "Software"), to deal in the Software without restriction, including
++ * without limitation the rights to use, copy, modify, merge, publish,
++ * distribute, sublicense, and/or sell copies of the Software, and to
++ * permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the
++ * next paragraph) shall be included in all copies or substantial
++ * portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
++ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++ *
++ */
++
++#include "drmP.h"
++#include "nouveau_drv.h"
++#include "nouveau_hw.h"
++
++static bool
++get_gpio_location(struct dcb_gpio_entry *ent, uint32_t *reg, uint32_t *shift,
++		  uint32_t *mask)
++{
++	if (ent->line < 2) {
++		*reg = NV_PCRTC_GPIO;
++		*shift = ent->line * 16;
++		*mask = 0x11;
++
++	} else if (ent->line < 10) {
++		*reg = NV_PCRTC_GPIO_EXT;
++		*shift = (ent->line - 2) * 4;
++		*mask = 0x3;
++
++	} else if (ent->line < 14) {
++		*reg = NV_PCRTC_850;
++		*shift = (ent->line - 10) * 4;
++		*mask = 0x3;
++
++	} else {
++		return false;
++	}
++
++	return true;
++}
++
++int
++nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
++{
++	struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
++	uint32_t reg, shift, mask, value;
++
++	if (!ent)
++		return -ENODEV;
++
++	if (!get_gpio_location(ent, &reg, &shift, &mask))
++		return -ENODEV;
++
++	value = NVReadCRTC(dev, 0, reg) >> shift;
++
++	return (ent->invert ? 1 : 0) ^ (value & 1);
++}
++
++int
++nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
++{
++	struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
++	uint32_t reg, shift, mask, value;
++
++	if (!ent)
++		return -ENODEV;
++
++	if (!get_gpio_location(ent, &reg, &shift, &mask))
++		return -ENODEV;
++
++	value = ((ent->invert ? 1 : 0) ^ (state ? 1 : 0)) << shift;
++	mask = ~(mask << shift);
++
++	NVWriteCRTC(dev, 0, reg, value | (NVReadCRTC(dev, 0, reg) & mask));
++
++	return 0;
++}
 diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
 new file mode 100644
-index 0000000..34f95c7
+index 0000000..009fa48
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv17_tv.c
-@@ -0,0 +1,689 @@
+@@ -0,0 +1,681 @@
 +/*
 + * Copyright (C) 2009 Francisco Jerez.
 + * All Rights Reserved.
@@ -27158,9 +27416,9 @@ index 0000000..34f95c7
 +{
 +	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
 +
-+	tv_enc->pin_mask = pin_mask;
++	tv_enc->pin_mask = pin_mask >> 28 & 0xe;
 +
-+	switch (pin_mask) {
++	switch (tv_enc->pin_mask) {
 +	case 0x2:
 +	case 0x4:
 +		tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Composite;
@@ -27331,7 +27589,6 @@ index 0000000..34f95c7
 +static void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)
 +{
 +	struct drm_device *dev = encoder->dev;
-+	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;
 +	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
 +
@@ -27356,15 +27613,8 @@ index 0000000..34f95c7
 +
 +	nv_load_ptv(dev, regs, 200);
 +
-+	if (dev_priv->chipset >= 0x34) {
-+		uint32_t *gpio_ext = &dev_priv->mode_reg.crtc_reg[0].gpio_ext;
-+
-+		*gpio_ext &= ~(3 << 20);
-+		if (mode == DRM_MODE_DPMS_ON)
-+			*gpio_ext |= 1 << 20;
-+
-+		NVWriteCRTC(dev, 0, NV_PCRTC_GPIO_EXT, *gpio_ext);
-+	}
++	nv17_gpio_set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON);
++	nv17_gpio_set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON);
 +
 +	nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
 +}
@@ -27419,7 +27669,7 @@ index 0000000..34f95c7
 +	dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1;
 +
 +	if (nv_arch(dev) == NV_40)
-+		dacclk |= 1 << 20;
++		dacclk |= 0x1a << 16;
 +
 +	if (tv_norm->kind == CTV_ENC_MODE) {
 +		dacclk |=  0x20;
@@ -28559,10 +28809,10 @@ index 0000000..d64683d
 +}
 diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
 new file mode 100644
-index 0000000..eeadc14
+index 0000000..18ba74f
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv20_graph.c
-@@ -0,0 +1,778 @@
+@@ -0,0 +1,780 @@
 +#include "drmP.h"
 +#include "drm.h"
 +#include "nouveau_drv.h"
@@ -29326,9 +29576,11 @@ index 0000000..eeadc14
 +	{ 0x004a, false, NULL }, /* gdirect */
 +	{ 0x009f, false, NULL }, /* imageblit (nv12) */
 +	{ 0x008a, false, NULL }, /* ifc */
++	{ 0x038a, false, NULL }, /* ifc (nv30) */
 +	{ 0x0089, false, NULL }, /* sifm */
 +	{ 0x0389, false, NULL }, /* sifm (nv30) */
 +	{ 0x0062, false, NULL }, /* surf2d */
++	{ 0x0362, false, NULL }, /* surf2d (nv30) */
 +	{ 0x0043, false, NULL }, /* rop */
 +	{ 0x0012, false, NULL }, /* beta1 */
 +	{ 0x0072, false, NULL }, /* beta4 */
@@ -33283,10 +33535,10 @@ index 0000000..fb5838e
 +
 diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
 new file mode 100644
-index 0000000..c95efbc
+index 0000000..8a1dd89
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv50_display.c
-@@ -0,0 +1,902 @@
+@@ -0,0 +1,994 @@
 +/*
 + * Copyright (C) 2008 Maarten Maathuis.
 + * All Rights Reserved.
@@ -33472,7 +33724,8 @@ index 0000000..c95efbc
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
 +	struct nouveau_channel *evo = dev_priv->evo;
-+	uint32_t val, ram_amount;
++	struct drm_connector *connector;
++	uint32_t val, ram_amount, hpd_en[2];
 +	uint64_t start;
 +	int ret, i;
 +
@@ -33649,9 +33902,29 @@ index 0000000..c95efbc
 +					     NV50_PDISPLAY_INTR_EN_CLK_UNK40));
 +
 +	/* enable hotplug interrupts */
-+	nv_wr32(dev, NV50_PCONNECTOR_HOTPLUG_CTRL, 0x7FFF7FFF);
-+	/* nv_wr32(dev, NV50_PCONNECTOR_HOTPLUG_INTR, 0x7FFF7FFF); */
++	hpd_en[0] = hpd_en[1] = 0;
++	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
++		struct nouveau_connector *conn = nouveau_connector(connector);
++		struct dcb_gpio_entry *gpio;
 +
++		if (connector->connector_type != DRM_MODE_CONNECTOR_DVII &&
++		    connector->connector_type != DRM_MODE_CONNECTOR_DVID &&
++		    connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
++			continue;
++
++		gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag);
++		if (!gpio)
++			continue;
++
++		hpd_en[gpio->line >> 4] |= (0x00010001 << (gpio->line & 0xf));
++	}
++
++	nv_wr32(dev, 0xe054, 0xffffffff);
++	nv_wr32(dev, 0xe050, hpd_en[0]);
++	if (dev_priv->chipset >= 0x90) {
++		nv_wr32(dev, 0xe074, 0xffffffff);
++		nv_wr32(dev, 0xe070, hpd_en[1]);
++	}
 +
 +	return 0;
 +}
@@ -33717,8 +33990,12 @@ index 0000000..c95efbc
 +	nv_wr32(dev, NV50_PDISPLAY_INTR_EN, 0x00000000);
 +
 +	/* disable hotplug interrupts */
-+	nv_wr32(dev, NV50_PCONNECTOR_HOTPLUG_INTR, 0);
-+
++	nv_wr32(dev, 0xe054, 0xffffffff);
++	nv_wr32(dev, 0xe050, 0x00000000);
++	if (dev_priv->chipset >= 0x90) {
++		nv_wr32(dev, 0xe074, 0xffffffff);
++		nv_wr32(dev, 0xe070, 0x00000000);
++	}
 +	return 0;
 +}
 +
@@ -33763,6 +34040,12 @@ index 0000000..c95efbc
 +	for (i = 0 ; i < dcb->entries; i++) {
 +		struct dcb_entry *entry = &dcb->entry[i];
 +
++		if (entry->location != DCB_LOC_ON_CHIP) {
++			NV_WARN(dev, "Off-chip encoder %d/%d unsupported\n",
++				entry->type, ffs(entry->or) - 1);
++			continue;
++		}
++
 +		switch (entry->type) {
 +		case OUTPUT_TMDS:
 +		case OUTPUT_LVDS:
@@ -33863,7 +34146,7 @@ index 0000000..c95efbc
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	uint32_t unk30 = nv_rd32(dev, NV50_PDISPLAY_UNK30_CTRL);
 +	uint32_t dac = 0, sor = 0;
-+	int head, i, or;
++	int head, i, or = 0, type = OUTPUT_ANY;
 +
 +	/* We're assuming that head 0 *or* head 1 will be active here,
 +	 * and not both.  I'm not sure if the hw will even signal both
@@ -33882,56 +34165,60 @@ index 0000000..c95efbc
 +	/* This assumes CRTCs are never bound to multiple encoders, which
 +	 * should be the case.
 +	 */
-+	for (i = 0; i < 3; i++) {
-+		if (nv50_display_mode_ctrl(dev, false, i) & (1 << head))
-+			dac |= (1 << i);
-+	}
++	for (i = 0; i < 3 && type == OUTPUT_ANY; i++) {
++		uint32_t mc = nv50_display_mode_ctrl(dev, false, i);
++		if (!(mc & (1 << head)))
++			continue;
 +
-+	for (i = 0; i < 4; i++) {
-+		if (nv50_display_mode_ctrl(dev, true, i) & (1 << head))
-+			sor |= (1 << i);
++		switch ((mc >> 8) & 0xf) {
++		case 0: type = OUTPUT_ANALOG; break;
++		case 1: type = OUTPUT_TV; break;
++		default:
++			NV_ERROR(dev, "unknown dac mode_ctrl: 0x%08x\n", dac);
++			return -1;
++		}
++
++		or = i;
 +	}
 +
-+	NV_DEBUG(dev, "dac: 0x%08x, sor: 0x%08x\n", dac, sor);
++	for (i = 0; i < 4 && type == OUTPUT_ANY; i++) {
++		uint32_t mc = nv50_display_mode_ctrl(dev, true, i);
++		if (!(mc & (1 << head)))
++			continue;
 +
-+	if (dac && sor) {
-+		NV_ERROR(dev, "multiple encoders: 0x%08x 0x%08x\n", dac, sor);
-+		return -1;
-+	} else
-+	if (dac) {
-+		or = ffs(dac) - 1;
-+		if (dac & ~(1 << or)) {
-+			NV_ERROR(dev, "multiple DAC: 0x%08x\n", dac);
-+			return -1;
-+		}
-+	} else
-+	if (sor) {
-+		or = ffs(sor) - 1;
-+		if (sor & ~(1 << or)) {
-+			NV_ERROR(dev, "multiple SOR: 0x%08x\n", sor);
++		switch ((mc >> 8) & 0xf) {
++		case 0: type = OUTPUT_LVDS; break;
++		case 1: type = OUTPUT_TMDS; break;
++		case 2: type = OUTPUT_TMDS; break;
++		case 5: type = OUTPUT_TMDS; break;
++		case 8: type = OUTPUT_DP; break;
++		case 9: type = OUTPUT_DP; break;
++		default:
++			NV_ERROR(dev, "unknown sor mode_ctrl: 0x%08x\n", sor);
 +			return -1;
 +		}
-+	} else {
-+		NV_ERROR(dev, "no encoders!\n");
++
++		or = i;
++	}
++
++	NV_DEBUG(dev, "type %d, or %d\n", type, or);
++	if (type == OUTPUT_ANY) {
++		NV_ERROR(dev, "unknown encoder!!\n");
 +		return -1;
 +	}
 +
 +	for (i = 0; i < dev_priv->vbios->dcb->entries; i++) {
 +		struct dcb_entry *dcbent = &dev_priv->vbios->dcb->entry[i];
 +
-+		if (dac && (dcbent->type != OUTPUT_ANALOG &&
-+			    dcbent->type != OUTPUT_TV))
++		if (dcbent->type != type)
 +			continue;
-+		else
-+		if (sor && (dcbent->type != OUTPUT_TMDS &&
-+			    dcbent->type != OUTPUT_LVDS))
++
++		if (!(dcbent->or & (1 << or)))
 +			continue;
 +
-+		if (dcbent->or & (1 << or)) {
-+			*phead = head;
-+			*pdcbent = dcbent;
-+			return 0;
-+		}
++		*phead = head;
++		*pdcbent = dcbent;
++		return 0;
 +	}
 +
 +	NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or);
@@ -33951,11 +34238,23 @@ index 0000000..c95efbc
 +	switch (dcbent->type) {
 +	case OUTPUT_LVDS:
 +		script = (mc >> 8) & 0xf;
-+		if (pxclk >= bios->fp.duallink_transition_clk)
-+			script |= 0x0100;
++		if (bios->pub.fp_no_ddc) {
++			if (bios->fp.dual_link)
++				script |= 0x0100;
++			if (bios->fp.if_is_24bit)
++				script |= 0x0200;
++		} else {
++			if (pxclk >= bios->fp.duallink_transition_clk) {
++				script |= 0x0100;
++				if (bios->fp.strapless_is_24bit & 2)
++					script |= 0x0200;
++			} else
++			if (bios->fp.strapless_is_24bit & 1)
++				script |= 0x0200;
++		}
 +
 +		if (nouveau_uscript_lvds >= 0) {
-+			NV_INFO(dev, "override script 0x%04x with 0x%04x"
++			NV_INFO(dev, "override script 0x%04x with 0x%04x "
 +				     "for output LVDS-%d\n", script,
 +				     nouveau_uscript_lvds, or);
 +			script = nouveau_uscript_lvds;
@@ -33967,7 +34266,7 @@ index 0000000..c95efbc
 +			script |= 0x0100;
 +
 +		if (nouveau_uscript_tmds >= 0) {
-+			NV_INFO(dev, "override script 0x%04x with 0x%04x"
++			NV_INFO(dev, "override script 0x%04x with 0x%04x "
 +				     "for output TMDS-%d\n", script,
 +				     nouveau_uscript_tmds, or);
 +			script = nouveau_uscript_tmds;
@@ -34139,12 +34438,57 @@ index 0000000..c95efbc
 +	nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR, 0x90000000);
 +}
 +
++static void
++nv50_display_irq_hotplug(struct drm_device *dev)
++{
++	struct drm_nouveau_private *dev_priv = dev->dev_private;
++	struct drm_connector *connector;
++	const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
++	uint32_t unplug_mask, plug_mask, change_mask;
++	uint32_t hpd0, hpd1 = 0;
++
++	hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050);
++	if (dev_priv->chipset >= 0x90)
++		hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070);
++
++	plug_mask   = (hpd0 & 0x0000ffff) | (hpd1 << 16);
++	unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000);
++	change_mask = plug_mask | unplug_mask;
++
++	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
++		struct nouveau_connector *nv_connector =
++			nouveau_connector(connector);
++		struct dcb_gpio_entry *gpio;
++		uint32_t reg;
++		bool plugged;
++
++		if (!nv_connector->dcb)
++			continue;
++
++		gpio = nouveau_bios_gpio_entry(dev, nv_connector->dcb->gpio_tag);
++		if (!gpio || !(change_mask & (1 << gpio->line)))
++			continue;
++
++		reg = nv_rd32(dev, gpio_reg[gpio->line >> 3]);
++		plugged = !!(reg & (4 << ((gpio->line & 7) << 2)));
++		NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un",
++			drm_get_connector_name(connector)) ;
++	}
++
++	nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
++	if (dev_priv->chipset >= 0x90)
++		nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
++}
++
 +void
 +nv50_display_irq_handler(struct drm_device *dev)
 +{
 +	struct drm_nouveau_private *dev_priv = dev->dev_private;
 +	uint32_t delayed = 0;
 +
++	while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG)
++		nv50_display_irq_hotplug(dev);
++
 +	while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
 +		uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
 +		uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
@@ -34171,7 +34515,7 @@ index 0000000..c95efbc
 +		if (clock) {
 +			nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
 +			if (!work_pending(&dev_priv->irq_work))
-+				schedule_work(&dev_priv->irq_work);
++				queue_work(dev_priv->wq, &dev_priv->irq_work);
 +			delayed |= clock;
 +			intr1 &= ~clock;
 +		}
@@ -63025,10 +63369,10 @@ index 0000000..e0a9c3f
 +}
 diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
 new file mode 100644
-index 0000000..d7fab7d
+index 0000000..019a1bf
 --- /dev/null
 +++ b/drivers/gpu/drm/nouveau/nv50_sor.c
-@@ -0,0 +1,265 @@
+@@ -0,0 +1,269 @@
 +/*
 + * Copyright (C) 2008 Maarten Maathuis.
 + * All Rights Reserved.
@@ -63186,9 +63530,13 @@ index 0000000..d7fab7d
 +
 +	switch (nv_encoder->dcb->type) {
 +	case OUTPUT_TMDS:
-+		mode_ctl |= NV50_EVO_SOR_MODE_CTRL_TMDS;
-+		if (adjusted_mode->clock > 165000)
-+			mode_ctl |= NV50_EVO_SOR_MODE_CTRL_TMDS_DUAL_LINK;
++		if (nv_encoder->dcb->tmdsconf.sor_link & 1) {
++			if (adjusted_mode->clock < 165000)
++				mode_ctl = 0x0100;
++			else
++				mode_ctl = 0x0500;
++		} else
++			mode_ctl = 0x0200;
 +		break;
 +	default:
 +		break;


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-12/kernel.spec,v
retrieving revision 1.1943
retrieving revision 1.1944
diff -u -p -r1.1943 -r1.1944
--- kernel.spec	1 Dec 2009 04:13:23 -0000	1.1943
+++ kernel.spec	1 Dec 2009 23:24:14 -0000	1.1944
@@ -2153,6 +2153,11 @@ fi
 # and build.
 
 %changelog
+* Wed Dec 02 2009 Ben Skeggs <bskeggs at redhat.com> 2.6.31.6-158
+- nouveau: more complete lvds script selection on >=G80 (rh#522690, rh#529859)
+- nouveau: more complete tmds script selection on >=G80 (rh#537853)
+- nouveau: TV detection fixes
+
 * Tue Dec 01 2009 Dave Airlie <airlied at redhat.com> 2.6.31.6-157
 - div/0 fix harder (#540593) - also ignore unposted GPUs with no BIOS
 




More information about the fedora-extras-commits mailing list