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
- Previous message (by thread): rpms/mdadm/F-11 mdadm.spec,1.72,1.73 mdmonitor.init,1.9,1.10
- Next message (by thread): rpms/rdma/devel rdma.conf, 1.1, 1.2 rdma.ifup-ib, 1.1, 1.2 rdma.init, 1.1, 1.2 rdma.spec, 1.4, 1.5
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
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 = ®p->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, ®, &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, ®, &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
- Previous message (by thread): rpms/mdadm/F-11 mdadm.spec,1.72,1.73 mdmonitor.init,1.9,1.10
- Next message (by thread): rpms/rdma/devel rdma.conf, 1.1, 1.2 rdma.ifup-ib, 1.1, 1.2 rdma.init, 1.1, 1.2 rdma.spec, 1.4, 1.5
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the fedora-extras-commits
mailing list