rpms/kernel/F-13 drm-nouveau-drm-fixed-header.patch, NONE, 1.1 drm-nouveau-updates.patch, 1.7, 1.8 kernel.spec, 1.2008, 1.2009

Ben Skeggs bskeggs at fedoraproject.org
Thu Apr 29 01:06:47 UTC 2010


Author: bskeggs

Update of /cvs/pkgs/rpms/kernel/F-13
In directory cvs01.phx2.fedoraproject.org:/tmp/cvs-serv26715

Modified Files:
	drm-nouveau-updates.patch kernel.spec 
Added Files:
	drm-nouveau-drm-fixed-header.patch 
Log Message:
* Thu Apr 29 2010 Ben Skeggs <bskeggs at redhat.com> 2.6.33.3-73
- nouveau: initial eDP support + DP suspend/resume fixes
- nouveau: fix monitor detection on certain chipsets with DP support
- nouveau: better CRTC PLL calculation on latest chipsets
- nouveau: send hotplug events down to userspace



drm-nouveau-drm-fixed-header.patch:
 drm_fixed.h |   68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 67 insertions(+), 1 deletion(-)

--- NEW FILE drm-nouveau-drm-fixed-header.patch ---
>From 98b5715348686cb2d9d695c5010d3831d99b934b Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs at redhat.com>
Date: Wed, 28 Apr 2010 15:19:10 +1000
Subject: [PATCH] drm-nouveau-drm-fixed-header

---
 drivers/gpu/drm/nouveau/drm_fixed.h |   67 +++++++++++++++++++++++++++++++++++
 1 files changed, 67 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpu/drm/nouveau/drm_fixed.h

diff --git a/drivers/gpu/drm/nouveau/drm_fixed.h b/drivers/gpu/drm/nouveau/drm_fixed.h
new file mode 100644
index 0000000..4a08a66
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/drm_fixed.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2009 Red Hat Inc.
+ *
+ * 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 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 HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Dave Airlie
+ */
+#ifndef DRM_FIXED_H
+#define DRM_FIXED_H
+
+typedef union dfixed {
+	u32 full;
+} fixed20_12;
+
+
+#define dfixed_const(A) (u32)(((A) << 12))/*  + ((B + 0.000122)*4096)) */
+#define dfixed_const_half(A) (u32)(((A) << 12) + 2048)
+#define dfixed_const_666(A) (u32)(((A) << 12) + 2731)
+#define dfixed_const_8(A) (u32)(((A) << 12) + 3277)
+#define dfixed_mul(A, B) ((u64)((u64)(A).full * (B).full + 2048) >> 12)
+#define dfixed_init(A) { .full = dfixed_const((A)) }
+#define dfixed_init_half(A) { .full = dfixed_const_half((A)) }
+#define dfixed_trunc(A) ((A).full >> 12)
+
+static inline u32 dfixed_floor(fixed20_12 A)
+{
+	u32 non_frac = dfixed_trunc(A);
+
+	return dfixed_const(non_frac);
+}
+
+static inline u32 dfixed_ceil(fixed20_12 A)
+{
+	u32 non_frac = dfixed_trunc(A);
+
+	if (A.full > dfixed_const(non_frac))
+		return dfixed_const(non_frac + 1);
+	else
+		return dfixed_const(non_frac);
+}
+
+static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
+{
+	u64 tmp = ((u64)A.full << 13);
+
+	do_div(tmp, B.full);
+	tmp += 1;
+	tmp /= 2;
+	return lower_32_bits(tmp);
+}
+#endif
-- 
1.7.0.1


drm-nouveau-updates.patch:
 Makefile            |    7 
 nouveau_bios.c      |  669 +++++++++-----
 nouveau_bios.h      |  132 +-
 nouveau_bo.c        |   68 -
 nouveau_calc.c      |    4 
 nouveau_channel.c   |   15 
 nouveau_connector.c |  163 ++-
 nouveau_connector.h |    3 
 nouveau_debugfs.c   |   18 
 nouveau_dma.c       |    5 
 nouveau_dp.c        |    8 
 nouveau_drv.c       |   14 
 nouveau_drv.h       |   59 -
 nouveau_encoder.h   |    3 
 nouveau_gem.c       |   55 -
 nouveau_hw.c        |    6 
 nouveau_i2c.c       |   23 
 nouveau_irq.c       |  615 ++++++++++++-
 nouveau_mem.c       |  124 +-
 nouveau_reg.h       |    1 
 nouveau_sgdma.c     |   18 
 nouveau_state.c     |   20 
 nv04_crtc.c         |    6 
 nv04_dac.c          |    8 
 nv04_dfp.c          |    4 
 nv04_display.c      |   49 -
 nv04_fbcon.c        |    6 
 nv04_fifo.c         |    5 
 nv04_tv.c           |    2 
 nv17_tv.c           |    6 
 nv40_fifo.c         |    7 
 nv40_graph.c        |   21 
 nv50_calc.c         |   88 +
 nv50_crtc.c         |   46 -
 nv50_dac.c          |    4 
 nv50_display.c      |  111 +-
 nv50_display.h      |    1 
 nv50_fb.c           |   32 
 nv50_fbcon.c        |   17 
 nv50_fifo.c         |    5 
 nv50_gpio.c         |   76 +
 nv50_graph.c        |  103 +-
 nv50_grctx.c        | 2383 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 nv50_instmem.c      |   18 
 nv50_sor.c          |   31 
 45 files changed, 4295 insertions(+), 764 deletions(-)

Index: drm-nouveau-updates.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-13/drm-nouveau-updates.patch,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -p -r1.7 -r1.8
--- drm-nouveau-updates.patch	15 Apr 2010 22:53:44 -0000	1.7
+++ drm-nouveau-updates.patch	29 Apr 2010 01:06:41 -0000	1.8
@@ -1,7 +1,7 @@
-From 34fdacaf7508f5fd7219b415b533bbb4c52dd300 Mon Sep 17 00:00:00 2001
+From 42258564f2bcbf1e389a758c9d1249296004469d Mon Sep 17 00:00:00 2001
 From: Marcin Slusarz <marcin.slusarz at gmail.com>
 Date: Wed, 17 Feb 2010 19:04:00 +0100
-Subject: [PATCH 1/2] drm-nouveau-updates
+Subject: [PATCH] drm-nouveau-updates
 MIME-Version: 1.0
 Content-Type: text/plain; charset=UTF-8
 Content-Transfer-Encoding: 8bit
@@ -393,10 +393,48 @@ This reverts commit b30083bdb990bcc2829f
 drm/nouveau: fix a nouveau_bo dereference after it's been destroyed
 
 Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: bios parser fixes for eDP boards
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nouveau: dump pll limits entries when debugging is on
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: output calculated crtc pll when debugging on
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: fix suspend/resume with DP outputs
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: store full dcb i2c entry from vbios
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: fix monitor detection on certain chipsets
+
+There appears to be some kind of switch on certain chips to control whether
+the DP auxch or traditional i2c bus will be operational on a connector,
+this commit hopefully fixes nouveau to do the right thing.
+
+Likely only relevent on chips with DP outputs.
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: send hotplug event to userspace
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
+
+drm/nv50: support fractional feedback divider on newer chips
+
+Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
 ---
- drivers/gpu/drm/nouveau/Makefile            |    6 +-
- drivers/gpu/drm/nouveau/nouveau_bios.c      |  486 ++++---
- drivers/gpu/drm/nouveau/nouveau_bios.h      |  131 +-
+ drivers/gpu/drm/nouveau/Makefile            |    7 +-
+ drivers/gpu/drm/nouveau/nouveau_bios.c      |  669 +++++---
+ drivers/gpu/drm/nouveau/nouveau_bios.h      |  132 +-
  drivers/gpu/drm/nouveau/nouveau_bo.c        |   68 +-
  drivers/gpu/drm/nouveau/nouveau_calc.c      |    4 +-
  drivers/gpu/drm/nouveau/nouveau_channel.c   |   15 +-
@@ -406,13 +444,14 @@ Signed-off-by: Ben Skeggs <bskeggs at redha
  drivers/gpu/drm/nouveau/nouveau_dma.c       |    5 +
  drivers/gpu/drm/nouveau/nouveau_dp.c        |    8 +-
  drivers/gpu/drm/nouveau/nouveau_drv.c       |   14 +-
- drivers/gpu/drm/nouveau/nouveau_drv.h       |   53 +-
- drivers/gpu/drm/nouveau/nouveau_encoder.h   |    1 +
+ drivers/gpu/drm/nouveau/nouveau_drv.h       |   59 +-
+ drivers/gpu/drm/nouveau/nouveau_encoder.h   |    3 +
  drivers/gpu/drm/nouveau/nouveau_gem.c       |   55 +-
  drivers/gpu/drm/nouveau/nouveau_hw.c        |    6 +-
- drivers/gpu/drm/nouveau/nouveau_i2c.c       |   10 +-
+ drivers/gpu/drm/nouveau/nouveau_i2c.c       |   23 +-
  drivers/gpu/drm/nouveau/nouveau_irq.c       |  615 +++++++-
  drivers/gpu/drm/nouveau/nouveau_mem.c       |  124 +-
+ drivers/gpu/drm/nouveau/nouveau_reg.h       |    1 +
  drivers/gpu/drm/nouveau/nouveau_sgdma.c     |   18 +
  drivers/gpu/drm/nouveau/nouveau_state.c     |   20 +-
  drivers/gpu/drm/nouveau/nv04_crtc.c         |    6 +-
@@ -425,8 +464,10 @@ Signed-off-by: Ben Skeggs <bskeggs at redha
  drivers/gpu/drm/nouveau/nv17_tv.c           |    6 +-
  drivers/gpu/drm/nouveau/nv40_fifo.c         |    7 +-
  drivers/gpu/drm/nouveau/nv40_graph.c        |   21 +
+ drivers/gpu/drm/nouveau/nv50_calc.c         |   88 +
+ drivers/gpu/drm/nouveau/nv50_crtc.c         |   46 +-
  drivers/gpu/drm/nouveau/nv50_dac.c          |    4 +-
- drivers/gpu/drm/nouveau/nv50_display.c      |   76 +-
+ drivers/gpu/drm/nouveau/nv50_display.c      |  111 +-
  drivers/gpu/drm/nouveau/nv50_display.h      |    1 +
  drivers/gpu/drm/nouveau/nv50_fb.c           |   32 +
  drivers/gpu/drm/nouveau/nv50_fbcon.c        |   17 +-
@@ -435,17 +476,18 @@ Signed-off-by: Ben Skeggs <bskeggs at redha
  drivers/gpu/drm/nouveau/nv50_graph.c        |  103 +-
  drivers/gpu/drm/nouveau/nv50_grctx.c        | 2383 +++++++++++++++++++++++++++
  drivers/gpu/drm/nouveau/nv50_instmem.c      |   18 +-
- drivers/gpu/drm/nouveau/nv50_sor.c          |   25 +-
- 42 files changed, 3961 insertions(+), 716 deletions(-)
+ drivers/gpu/drm/nouveau/nv50_sor.c          |   30 +-
+ 45 files changed, 4295 insertions(+), 763 deletions(-)
+ create mode 100644 drivers/gpu/drm/nouveau/nv50_calc.c
  create mode 100644 drivers/gpu/drm/nouveau/nv50_fb.c
  create mode 100644 drivers/gpu/drm/nouveau/nv50_gpio.c
  create mode 100644 drivers/gpu/drm/nouveau/nv50_grctx.c
 
 diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
-index 48c290b..453df3f 100644
+index 48c290b..acd31ed 100644
 --- a/drivers/gpu/drm/nouveau/Makefile
 +++ b/drivers/gpu/drm/nouveau/Makefile
-@@ -12,17 +12,17 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
+@@ -12,17 +12,18 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
               nouveau_dp.o nouveau_grctx.o \
               nv04_timer.o \
               nv04_mc.o nv40_mc.o nv50_mc.o \
@@ -462,15 +504,24 @@ index 48c290b..453df3f 100644
               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 \
 -             nv17_gpio.o
-+             nv17_gpio.o nv50_gpio.o
++             nv17_gpio.o nv50_gpio.o \
++	     nv50_calc.o
  
  nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
  nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
 diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
-index 0e9cd1d..4b0d67c 100644
+index 0e9cd1d..97d63e1 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
-@@ -311,11 +311,11 @@ valid_reg(struct nvbios *bios, uint32_t reg)
+@@ -26,6 +26,7 @@
+ #define NV_DEBUG_NOTRACE
+ #include "nouveau_drv.h"
+ #include "nouveau_hw.h"
++#include "nouveau_encoder.h"
+ 
+ /* these defines are made up */
+ #define NV_CIO_CRE_44_HEADA 0x0
+@@ -311,11 +312,11 @@ valid_reg(struct nvbios *bios, uint32_t reg)
  
  	/* C51 has misaligned regs on purpose. Marvellous */
  	if (reg & 0x2 ||
@@ -484,7 +535,7 @@ index 0e9cd1d..4b0d67c 100644
  	    reg != 0x130d && reg != 0x1311 && reg != 0x60081d)
  		NV_WARN(dev, "=== C51 misaligned reg 0x%08X not verified ===\n",
  			reg);
-@@ -420,7 +420,7 @@ bios_wr32(struct nvbios *bios, uint32_t reg, uint32_t data)
+@@ -420,7 +421,7 @@ bios_wr32(struct nvbios *bios, uint32_t reg, uint32_t data)
  	LOG_OLD_VALUE(bios_rd32(bios, reg));
  	BIOSLOG(bios, "	Write: Reg: 0x%08X, Data: 0x%08X\n", reg, data);
  
@@ -493,7 +544,7 @@ index 0e9cd1d..4b0d67c 100644
  		still_alive();
  		nv_wr32(bios->dev, reg, data);
  	}
-@@ -647,7 +647,7 @@ nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk)
+@@ -647,7 +648,7 @@ nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk)
  	reg0 = (reg0 & 0xfff8ffff) | (pll.log2P << 16);
  	reg1 = (reg1 & 0xffff0000) | (pll.N1 << 8) | pll.M1;
  
@@ -502,7 +553,7 @@ index 0e9cd1d..4b0d67c 100644
  		still_alive();
  		nv_wr32(dev, reg + 4, reg1);
  		nv_wr32(dev, reg + 0, reg0);
-@@ -689,7 +689,7 @@ setPLL(struct nvbios *bios, uint32_t reg, uint32_t clk)
+@@ -689,7 +690,7 @@ setPLL(struct nvbios *bios, uint32_t reg, uint32_t clk)
  static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -511,7 +562,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	/*
  	 * For the results of this function to be correct, CR44 must have been
-@@ -700,7 +700,7 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
+@@ -700,7 +701,7 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
  
  	uint8_t dcb_entry = NVReadVgaCrtc5758(dev, bios->state.crtchead, 0);
  
@@ -520,7 +571,7 @@ index 0e9cd1d..4b0d67c 100644
  		NV_ERROR(dev, "CR58 doesn't have a valid DCB entry currently "
  				"(%02X)\n", dcb_entry);
  		dcb_entry = 0x7f;	/* unused / invalid marker */
-@@ -713,25 +713,26 @@ static struct nouveau_i2c_chan *
+@@ -713,25 +714,26 @@ static struct nouveau_i2c_chan *
  init_i2c_device_find(struct drm_device *dev, int i2c_index)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -552,7 +603,7 @@ index 0e9cd1d..4b0d67c 100644
  {
  	/*
  	 * For mlv < 0x80, it is an index into a table of TMDS base addresses.
-@@ -744,6 +745,7 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
+@@ -744,6 +746,7 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
  	 */
  
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -560,7 +611,7 @@ index 0e9cd1d..4b0d67c 100644
  	const int pramdac_offset[13] = {
  		0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
  	const uint32_t pramdac_table[4] = {
-@@ -756,13 +758,12 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
+@@ -756,13 +759,12 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
  		dcb_entry = dcb_entry_idx_from_crtchead(dev);
  		if (dcb_entry == 0x7f)
  			return 0;
@@ -576,7 +627,134 @@ index 0e9cd1d..4b0d67c 100644
  			NV_ERROR(dev, "Magic Lookup Value too big (%02X)\n",
  									mlv);
  			return 0;
-@@ -2572,48 +2573,34 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+@@ -1066,6 +1068,126 @@ init_io_flag_condition(struct nvbios *bios, uint16_t offset,
+ }
+ 
+ static int
++init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
++{
++	/*
++	 * INIT_DP_CONDITION   opcode: 0x3A ('')
++	 *
++	 * offset      (8 bit): opcode
++	 * offset + 1  (8 bit): "sub" opcode
++	 * offset + 2  (8 bit): unknown
++	 *
++	 */
++
++	struct bit_displayport_encoder_table *dpe = NULL;
++	struct dcb_entry *dcb = bios->display.output;
++	struct drm_device *dev = bios->dev;
++	uint8_t cond = bios->data[offset + 1];
++	int dummy;
++
++	BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond);
++
++	if (!iexec->execute)
++		return 3;
++
++	dpe = nouveau_bios_dp_table(dev, dcb, &dummy);
++	if (!dpe) {
++		NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset);
++		return -EINVAL;
++	}
++
++	switch (cond) {
++	case 0:
++	{
++		struct dcb_connector_table_entry *ent =
++			&bios->dcb.connector.entry[dcb->connector];
++
++		if (ent->type != DCB_CONNECTOR_eDP)
++			iexec->execute = false;
++	}
++		break;
++	case 1:
++	case 2:
++		if (!(dpe->unknown & cond))
++			iexec->execute = false;
++		break;
++	case 5:
++	{
++		struct nouveau_i2c_chan *auxch;
++		int ret;
++
++		auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index);
++		if (!auxch)
++			return -ENODEV;
++
++		ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1);
++		if (ret)
++			return ret;
++
++		if (cond & 1)
++			iexec->execute = false;
++	}
++		break;
++	default:
++		NV_WARN(dev, "0x%04X: unknown INIT_3A op: %d\n", offset, cond);
++		break;
++	}
++
++	if (iexec->execute)
++		BIOSLOG(bios, "0x%04X: continuing to execute\n", offset);
++	else
++		BIOSLOG(bios, "0x%04X: skipping following commands\n", offset);
++
++	return 3;
++}
++
++static int
++init_op_3b(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
++{
++	/*
++	 * INIT_3B   opcode: 0x3B ('')
++	 *
++	 * offset      (8 bit): opcode
++	 * offset + 1  (8 bit): crtc index
++	 *
++	 */
++
++	uint8_t or = ffs(bios->display.output->or) - 1;
++	uint8_t index = bios->data[offset + 1];
++	uint8_t data;
++
++	if (!iexec->execute)
++		return 2;
++
++	data = bios_idxprt_rd(bios, 0x3d4, index);
++	bios_idxprt_wr(bios, 0x3d4, index, data & ~(1 << or));
++	return 2;
++}
++
++static int
++init_op_3c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
++{
++	/*
++	 * INIT_3C   opcode: 0x3C ('')
++	 *
++	 * offset      (8 bit): opcode
++	 * offset + 1  (8 bit): crtc index
++	 *
++	 */
++
++	uint8_t or = ffs(bios->display.output->or) - 1;
++	uint8_t index = bios->data[offset + 1];
++	uint8_t data;
++
++	if (!iexec->execute)
++		return 2;
++
++	data = bios_idxprt_rd(bios, 0x3d4, index);
++	bios_idxprt_wr(bios, 0x3d4, index, data | (1 << or));
++	return 2;
++}
++
++static int
+ init_idx_addr_latched(struct nvbios *bios, uint16_t offset,
+ 		      struct init_exec *iexec)
+ {
+@@ -2572,48 +2694,34 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
  	 * each GPIO according to various values listed in each entry
  	 */
  
@@ -593,32 +771,31 @@ index 0e9cd1d..4b0d67c 100644
 -	if (bios->bdcb.version != 0x40) {
 -		NV_ERROR(bios->dev, "DCB table not version 4.0\n");
 -		return 0;
+-	}
+-
+-	if (!bios->bdcb.gpio_table_ptr) {
+-		NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n");
+-		return 0;
 +	if (dev_priv->card_type != NV_50) {
 +		NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
 +		return -ENODEV;
  	}
  
--	if (!bios->bdcb.gpio_table_ptr) {
--		NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n");
--		return 0;
--	}
-+	if (!iexec->execute)
-+		return 1;
- 
 -	gpio_entry = gpio_table + gpio_table[1];
 -	for (i = 0; i < gpio_table[2]; i++, gpio_entry += gpio_table[3]) {
 -		uint32_t entry = ROM32(gpio_entry[0]), r, s, v;
 -		int line = (entry & 0x0000001f);
++	if (!iexec->execute)
++		return 1;
+ 
+-		BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, entry);
 +	for (i = 0; i < bios->dcb.gpio.entries; i++) {
 +		struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i];
 +		uint32_t r, s, v;
  
--		BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, entry);
-+		BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry);
- 
 -		if ((entry & 0x0000ff00) == 0x0000ff00)
 -			continue;
-+		nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default);
++		BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry);
  
 -		r = nv50_gpio_reg[line >> 3];
 -		s = (line & 0x07) << 2;
@@ -628,7 +805,8 @@ index 0e9cd1d..4b0d67c 100644
 -		else
 -			v |= (((entry & 0x18000000) >> 27) ^ 2) << s;
 -		bios_wr32(bios, r, v);
--
++		nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default);
+ 
 -		r = nv50_gpio_ctl[line >> 4];
 -		s = (line & 0x0f);
 +		/* The NVIDIA binary driver doesn't appear to actually do
@@ -643,7 +821,17 @@ index 0e9cd1d..4b0d67c 100644
  		case 1:
  			v |= (0x00000001 << s);
  			break;
-@@ -3123,7 +3110,7 @@ run_digital_op_script(struct drm_device *dev, uint16_t scriptptr,
+@@ -2947,6 +3055,9 @@ static struct init_tbl_entry itbl_entry[] = {
+ 	{ "INIT_COPY"                         , 0x37, init_copy                       },
+ 	{ "INIT_NOT"                          , 0x38, init_not                        },
+ 	{ "INIT_IO_FLAG_CONDITION"            , 0x39, init_io_flag_condition          },
++	{ "INIT_DP_CONDITION"                 , 0x3A, init_dp_condition               },
++	{ "INIT_OP_3B"                        , 0x3B, init_op_3b                      },
++	{ "INIT_OP_3C"                        , 0x3C, init_op_3c                      },
+ 	{ "INIT_INDEX_ADDRESS_LATCHED"        , 0x49, init_idx_addr_latched           },
+ 	{ "INIT_IO_RESTRICT_PLL2"             , 0x4A, init_io_restrict_pll2           },
+ 	{ "INIT_PLL2"                         , 0x4B, init_pll2                       },
+@@ -3123,7 +3234,7 @@ run_digital_op_script(struct drm_device *dev, uint16_t scriptptr,
  		      struct dcb_entry *dcbent, int head, bool dl)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -652,7 +840,7 @@ index 0e9cd1d..4b0d67c 100644
  	struct init_exec iexec = {true, false};
  
  	NV_TRACE(dev, "0x%04X: Parsing digital output script table\n",
-@@ -3140,7 +3127,7 @@ run_digital_op_script(struct drm_device *dev, uint16_t scriptptr,
+@@ -3140,7 +3251,7 @@ run_digital_op_script(struct drm_device *dev, uint16_t scriptptr,
  static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entry *dcbent, int head, enum LVDS_script script)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -661,7 +849,7 @@ index 0e9cd1d..4b0d67c 100644
  	uint8_t sub = bios->data[bios->fp.xlated_entry + script] + (bios->fp.link_c_increment && dcbent->or & OUTPUT_C ? 1 : 0);
  	uint16_t scriptofs = ROM16(bios->data[bios->init_script_tbls_ptr + sub * 2]);
  
-@@ -3194,10 +3181,9 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int
+@@ -3194,10 +3305,9 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int
  	 * of a list of pxclks and script pointers.
  	 */
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -673,7 +861,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	/*
  	 * For now we assume version 3.0 table - g80 support will need some
-@@ -3216,26 +3202,29 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int
+@@ -3216,26 +3326,29 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int
  		scriptptr = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 11 + outputset * 2]);
  		break;
  	case LVDS_RESET:
@@ -714,7 +902,7 @@ index 0e9cd1d..4b0d67c 100644
  		if (!clktable) {
  			NV_ERROR(dev, "Pixel clock comparison table not found\n");
  			return -ENOENT;
-@@ -3261,7 +3250,7 @@ int call_lvds_script(struct drm_device *dev, struct dcb_entry *dcbent, int head,
+@@ -3261,7 +3374,7 @@ int call_lvds_script(struct drm_device *dev, struct dcb_entry *dcbent, int head,
  	 */
  
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -723,7 +911,7 @@ index 0e9cd1d..4b0d67c 100644
  	uint8_t lvds_ver = bios->data[bios->fp.lvdsmanufacturerpointer];
  	uint32_t sel_clk_binding, sel_clk;
  	int ret;
-@@ -3395,7 +3384,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
+@@ -3395,7 +3508,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
  #ifndef __powerpc__
  		NV_ERROR(dev, "Pointer to flat panel table invalid\n");
  #endif
@@ -732,7 +920,7 @@ index 0e9cd1d..4b0d67c 100644
  		return 0;
  	}
  
-@@ -3428,7 +3417,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
+@@ -3428,7 +3541,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
  		 * fptable[4] is the minimum
  		 * RAMDAC_FP_HCRTC -> RAMDAC_FP_HSYNC_START gap
  		 */
@@ -741,7 +929,7 @@ index 0e9cd1d..4b0d67c 100644
  		ofs = -7;
  		break;
  	default:
-@@ -3467,7 +3456,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
+@@ -3467,7 +3580,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
  
  	/* nv4x cards need both a strap value and fpindex of 0xf to use DDC */
  	if (lth.lvds_ver > 0x10)
@@ -750,7 +938,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	/*
  	 * If either the strap or xlated fpindex value are 0xf there is no
-@@ -3491,7 +3480,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
+@@ -3491,7 +3604,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
  bool nouveau_bios_fp_mode(struct drm_device *dev, struct drm_display_mode *mode)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -759,7 +947,7 @@ index 0e9cd1d..4b0d67c 100644
  	uint8_t *mode_entry = &bios->data[bios->fp.mode_ptr];
  
  	if (!mode)	/* just checking whether we can produce a mode */
-@@ -3562,11 +3551,11 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
+@@ -3562,11 +3675,11 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
  	 * until later, when this function should be called with non-zero pxclk
  	 */
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -773,7 +961,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	ret = parse_lvds_manufacturer_table_header(dev, bios, &lth);
  	if (ret)
-@@ -3637,37 +3626,40 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
+@@ -3637,37 +3750,40 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
  		*if_is_24bit = bios->data[lvdsofs] & 16;
  		break;
  	case 0x30:
@@ -829,7 +1017,7 @@ index 0e9cd1d..4b0d67c 100644
  	/* set dual_link flag for EDID case */
  	if (pxclk && (chip_version < 0x25 || chip_version > 0x28))
  		bios->fp.dual_link = (pxclk >= bios->fp.duallink_transition_clk);
-@@ -3682,7 +3674,7 @@ bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent,
+@@ -3682,7 +3798,7 @@ bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent,
  			 uint16_t record, int record_len, int record_nr)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -838,7 +1026,7 @@ index 0e9cd1d..4b0d67c 100644
  	uint32_t entry;
  	uint16_t table;
  	int i, v;
-@@ -3716,7 +3708,7 @@ nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
+@@ -3716,7 +3832,7 @@ nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
  		      int *length)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -847,7 +1035,7 @@ index 0e9cd1d..4b0d67c 100644
  	uint8_t *table;
  
  	if (!bios->display.dp_table_ptr) {
-@@ -3725,7 +3717,7 @@ nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
+@@ -3725,7 +3841,7 @@ nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
  	}
  	table = &bios->data[bios->display.dp_table_ptr];
  
@@ -856,7 +1044,7 @@ index 0e9cd1d..4b0d67c 100644
  		NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n",
  			 table[0]);
  		return NULL;
-@@ -3765,7 +3757,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
+@@ -3765,7 +3881,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
  	 */
  
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -865,7 +1053,7 @@ index 0e9cd1d..4b0d67c 100644
  	uint8_t *table = &bios->data[bios->display.script_table_ptr];
  	uint8_t *otable = NULL;
  	uint16_t script;
-@@ -3918,8 +3910,8 @@ int run_tmds_table(struct drm_device *dev, struct dcb_entry *dcbent, int head, i
+@@ -3918,8 +4034,8 @@ int run_tmds_table(struct drm_device *dev, struct dcb_entry *dcbent, int head, i
  	 */
  
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -876,7 +1064,7 @@ index 0e9cd1d..4b0d67c 100644
  	uint16_t clktable = 0, scriptptr;
  	uint32_t sel_clk_binding, sel_clk;
  
-@@ -3978,8 +3970,8 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
+@@ -3978,8 +4094,8 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
  	 */
  
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -887,7 +1075,65 @@ index 0e9cd1d..4b0d67c 100644
  	uint8_t pll_lim_ver = 0, headerlen = 0, recordlen = 0, entries = 0;
  	uint32_t crystal_strap_mask, crystal_straps;
  
-@@ -4332,7 +4324,7 @@ static void parse_bios_version(struct drm_device *dev, struct nvbios *bios, uint
+@@ -4293,31 +4409,32 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
+ 			break;
+ 		}
+ 
+-#if 0 /* for easy debugging */
+-	ErrorF("pll.vco1.minfreq: %d\n", pll_lim->vco1.minfreq);
+-	ErrorF("pll.vco1.maxfreq: %d\n", pll_lim->vco1.maxfreq);
+-	ErrorF("pll.vco2.minfreq: %d\n", pll_lim->vco2.minfreq);
+-	ErrorF("pll.vco2.maxfreq: %d\n", pll_lim->vco2.maxfreq);
+-
+-	ErrorF("pll.vco1.min_inputfreq: %d\n", pll_lim->vco1.min_inputfreq);
+-	ErrorF("pll.vco1.max_inputfreq: %d\n", pll_lim->vco1.max_inputfreq);
+-	ErrorF("pll.vco2.min_inputfreq: %d\n", pll_lim->vco2.min_inputfreq);
+-	ErrorF("pll.vco2.max_inputfreq: %d\n", pll_lim->vco2.max_inputfreq);
+-
+-	ErrorF("pll.vco1.min_n: %d\n", pll_lim->vco1.min_n);
+-	ErrorF("pll.vco1.max_n: %d\n", pll_lim->vco1.max_n);
+-	ErrorF("pll.vco1.min_m: %d\n", pll_lim->vco1.min_m);
+-	ErrorF("pll.vco1.max_m: %d\n", pll_lim->vco1.max_m);
+-	ErrorF("pll.vco2.min_n: %d\n", pll_lim->vco2.min_n);
+-	ErrorF("pll.vco2.max_n: %d\n", pll_lim->vco2.max_n);
+-	ErrorF("pll.vco2.min_m: %d\n", pll_lim->vco2.min_m);
+-	ErrorF("pll.vco2.max_m: %d\n", pll_lim->vco2.max_m);
+-
+-	ErrorF("pll.max_log2p: %d\n", pll_lim->max_log2p);
+-	ErrorF("pll.log2p_bias: %d\n", pll_lim->log2p_bias);
+-
+-	ErrorF("pll.refclk: %d\n", pll_lim->refclk);
+-#endif
++	NV_DEBUG(dev, "pll.vco1.minfreq: %d\n", pll_lim->vco1.minfreq);
++	NV_DEBUG(dev, "pll.vco1.maxfreq: %d\n", pll_lim->vco1.maxfreq);
++	NV_DEBUG(dev, "pll.vco1.min_inputfreq: %d\n", pll_lim->vco1.min_inputfreq);
++	NV_DEBUG(dev, "pll.vco1.max_inputfreq: %d\n", pll_lim->vco1.max_inputfreq);
++	NV_DEBUG(dev, "pll.vco1.min_n: %d\n", pll_lim->vco1.min_n);
++	NV_DEBUG(dev, "pll.vco1.max_n: %d\n", pll_lim->vco1.max_n);
++	NV_DEBUG(dev, "pll.vco1.min_m: %d\n", pll_lim->vco1.min_m);
++	NV_DEBUG(dev, "pll.vco1.max_m: %d\n", pll_lim->vco1.max_m);
++	if (pll_lim->vco2.maxfreq) {
++		NV_DEBUG(dev, "pll.vco2.minfreq: %d\n", pll_lim->vco2.minfreq);
++		NV_DEBUG(dev, "pll.vco2.maxfreq: %d\n", pll_lim->vco2.maxfreq);
++		NV_DEBUG(dev, "pll.vco2.min_inputfreq: %d\n", pll_lim->vco2.min_inputfreq);
++		NV_DEBUG(dev, "pll.vco2.max_inputfreq: %d\n", pll_lim->vco2.max_inputfreq);
++		NV_DEBUG(dev, "pll.vco2.min_n: %d\n", pll_lim->vco2.min_n);
++		NV_DEBUG(dev, "pll.vco2.max_n: %d\n", pll_lim->vco2.max_n);
++		NV_DEBUG(dev, "pll.vco2.min_m: %d\n", pll_lim->vco2.min_m);
++		NV_DEBUG(dev, "pll.vco2.max_m: %d\n", pll_lim->vco2.max_m);
++	}
++	if (!pll_lim->max_p) {
++		NV_DEBUG(dev, "pll.max_log2p: %d\n", pll_lim->max_log2p);
++		NV_DEBUG(dev, "pll.log2p_bias: %d\n", pll_lim->log2p_bias);
++	} else {
++		NV_DEBUG(dev, "pll.min_p: %d\n", pll_lim->min_p);
++		NV_DEBUG(dev, "pll.max_p: %d\n", pll_lim->max_p);
++	}
++	NV_DEBUG(dev, "pll.refclk: %d\n", pll_lim->refclk);
+ 
+ 	return 0;
+ }
+@@ -4332,7 +4449,7 @@ static void parse_bios_version(struct drm_device *dev, struct nvbios *bios, uint
  	 */
  
  	bios->major_version = bios->data[offset + 3];
@@ -896,7 +1142,7 @@ index 0e9cd1d..4b0d67c 100644
  	NV_TRACE(dev, "Bios version %02x.%02x.%02x.%02x\n",
  		 bios->data[offset + 3], bios->data[offset + 2],
  		 bios->data[offset + 1], bios->data[offset]);
-@@ -4402,7 +4394,7 @@ static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
+@@ -4402,7 +4519,7 @@ static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
  	}
  
  	/* First entry is normal dac, 2nd tv-out perhaps? */
@@ -905,7 +1151,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	return 0;
  }
-@@ -4526,8 +4518,8 @@ static int parse_bit_i_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
+@@ -4526,8 +4643,8 @@ static int parse_bit_i_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
  		return -ENOSYS;
  	}
  
@@ -916,7 +1162,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	return 0;
  }
-@@ -4796,11 +4788,11 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
+@@ -4796,11 +4913,11 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
  	uint16_t legacy_scripts_offset, legacy_i2c_offset;
  
  	/* load needed defaults in case we can't parse this info */
@@ -933,7 +1179,7 @@ index 0e9cd1d..4b0d67c 100644
  	bios->fmaxvco = 256000;
  	bios->fminvco = 128000;
  	bios->fp.duallink_transition_clk = 90000;
-@@ -4907,10 +4899,10 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
+@@ -4907,10 +5024,10 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
  	bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset];
  	bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1];
  	bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2];
@@ -948,7 +1194,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	if (bmplength > 74) {
  		bios->fmaxvco = ROM32(bmp[67]);
-@@ -4984,7 +4976,8 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
+@@ -4984,7 +5101,8 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
  		else
  			NV_WARN(dev,
  				"DCB I2C table has more entries than indexable "
@@ -958,7 +1204,7 @@ index 0e9cd1d..4b0d67c 100644
  		entry_len = i2ctable[3];
  		/* [4] is i2c_default_indices, read in parse_dcb_table() */
  	}
-@@ -5000,8 +4993,8 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
+@@ -5000,8 +5118,8 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
  
  	if (index == 0xf)
  		return 0;
@@ -969,7 +1215,22 @@ index 0e9cd1d..4b0d67c 100644
  			 index, i2ctable[2]);
  		return -ENOENT;
  	}
-@@ -5036,7 +5029,7 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
+@@ -5023,8 +5141,12 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
+ 			rdofs = wrofs = 0;
+ 	}
+ 
+-	if (dcb_i2c_ver >= 0x40 && port_type != 5 && port_type != 6)
+-		NV_WARN(dev, "DCB I2C table has port type %d\n", port_type);
++	if (dcb_i2c_ver >= 0x40) {
++		if (port_type != 5 && port_type != 6)
++			NV_WARN(dev, "DCB I2C table has port type %d\n", port_type);
++
++		i2c->entry = ROM32(i2ctable[headerlen + recordoffset + entry_len * index]);
++	}
+ 
+ 	i2c->port_type = port_type;
+ 	i2c->read = i2ctable[headerlen + recordoffset + rdofs + entry_len * index];
+@@ -5036,7 +5158,7 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
  static struct dcb_gpio_entry *
  new_gpio_entry(struct nvbios *bios)
  {
@@ -978,7 +1239,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	return &gpio->entry[gpio->entries++];
  }
-@@ -5045,14 +5038,14 @@ struct dcb_gpio_entry *
+@@ -5045,14 +5167,14 @@ 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;
@@ -997,7 +1258,7 @@ index 0e9cd1d..4b0d67c 100644
  	}
  
  	return NULL;
-@@ -5075,32 +5068,32 @@ parse_dcb30_gpio_entry(struct nvbios *bios, uint16_t offset)
+@@ -5075,32 +5197,32 @@ parse_dcb30_gpio_entry(struct nvbios *bios, uint16_t offset)
  	gpio->tag = tag;
  	gpio->line = line;
  	gpio->invert = flags != 4;
@@ -1040,7 +1301,7 @@ index 0e9cd1d..4b0d67c 100644
  	uint8_t *gpio_table = &bios->data[gpio_table_ptr];
  	int header_len = gpio_table[1],
  	    entries = gpio_table[2],
-@@ -5108,7 +5101,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
+@@ -5108,7 +5230,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
  	void (*parse_entry)(struct nvbios *, uint16_t) = NULL;
  	int i;
  
@@ -1049,7 +1310,7 @@ index 0e9cd1d..4b0d67c 100644
  		if (gpio_table_ptr && entry_len != 4) {
  			NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
  			return;
-@@ -5116,7 +5109,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
+@@ -5116,7 +5238,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
  
  		parse_entry = parse_dcb40_gpio_entry;
  
@@ -1058,7 +1319,7 @@ index 0e9cd1d..4b0d67c 100644
  		if (gpio_table_ptr && entry_len != 2) {
  			NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
  			return;
-@@ -5124,7 +5117,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
+@@ -5124,7 +5246,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
  
  		parse_entry = parse_dcb30_gpio_entry;
  
@@ -1067,7 +1328,7 @@ index 0e9cd1d..4b0d67c 100644
  		/*
  		 * DCBs older than v3.0 don't really have a GPIO
  		 * table, instead they keep some GPIO info at fixed
-@@ -5158,30 +5151,82 @@ struct dcb_connector_table_entry *
+@@ -5158,30 +5280,82 @@ struct dcb_connector_table_entry *
  nouveau_bios_connector_entry(struct drm_device *dev, int index)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1156,7 +1417,7 @@ index 0e9cd1d..4b0d67c 100644
  		NV_DEBUG_KMS(dev, "No DCB connector table present\n");
  		return;
  	}
-@@ -5199,12 +5244,14 @@ parse_dcb_connector_table(struct nvbios *bios)
+@@ -5199,12 +5373,14 @@ parse_dcb_connector_table(struct nvbios *bios)
  	entry = conntab + conntab[1];
  	cte = &ct->entry[0];
  	for (i = 0; i < conntab[2]; i++, entry += conntab[3], cte++) {
@@ -1172,7 +1433,7 @@ index 0e9cd1d..4b0d67c 100644
  		switch (cte->entry & 0x00033000) {
  		case 0x00001000:
  			cte->gpio_tag = 0x07;
-@@ -5226,12 +5273,43 @@ parse_dcb_connector_table(struct nvbios *bios)
+@@ -5226,12 +5402,43 @@ parse_dcb_connector_table(struct nvbios *bios)
  		if (cte->type == 0xff)
  			continue;
  
@@ -1217,7 +1478,7 @@ index 0e9cd1d..4b0d67c 100644
  {
  	struct dcb_entry *entry = &dcb->entry[dcb->entries];
  
-@@ -5241,7 +5319,7 @@ static struct dcb_entry *new_dcb_entry(struct parsed_dcb *dcb)
+@@ -5241,7 +5448,7 @@ static struct dcb_entry *new_dcb_entry(struct parsed_dcb *dcb)
  	return entry;
  }
  
@@ -1226,7 +1487,7 @@ index 0e9cd1d..4b0d67c 100644
  {
  	struct dcb_entry *entry = new_dcb_entry(dcb);
  
-@@ -5252,7 +5330,7 @@ static void fabricate_vga_output(struct parsed_dcb *dcb, int i2c, int heads)
+@@ -5252,7 +5459,7 @@ static void fabricate_vga_output(struct parsed_dcb *dcb, int i2c, int heads)
  	/* "or" mostly unused in early gen crt modesetting, 0 is fine */
  }
  
@@ -1235,7 +1496,7 @@ index 0e9cd1d..4b0d67c 100644
  {
  	struct dcb_entry *entry = new_dcb_entry(dcb);
  
-@@ -5279,7 +5357,7 @@ static void fabricate_dvi_i_output(struct parsed_dcb *dcb, bool twoHeads)
+@@ -5279,7 +5486,7 @@ static void fabricate_dvi_i_output(struct parsed_dcb *dcb, bool twoHeads)
  #endif
  }
  
@@ -1244,7 +1505,7 @@ index 0e9cd1d..4b0d67c 100644
  {
  	struct dcb_entry *entry = new_dcb_entry(dcb);
  
-@@ -5290,13 +5368,13 @@ static void fabricate_tv_output(struct parsed_dcb *dcb, bool twoHeads)
+@@ -5290,13 +5497,13 @@ static void fabricate_tv_output(struct parsed_dcb *dcb, bool twoHeads)
  }
  
  static bool
@@ -1260,7 +1521,7 @@ index 0e9cd1d..4b0d67c 100644
  		entry->connector = (conn >> 12) & 0xf;
  	entry->bus = (conn >> 16) & 0xf;
  	entry->location = (conn >> 20) & 0x3;
-@@ -5314,7 +5392,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5314,7 +5521,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  		 * Although the rest of a CRT conf dword is usually
  		 * zeros, mac biosen have stuff there so we must mask
  		 */
@@ -1269,7 +1530,7 @@ index 0e9cd1d..4b0d67c 100644
  					 (conf & 0xffff) * 10 :
  					 (conf & 0xff) * 10000;
  		break;
-@@ -5323,7 +5401,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5323,7 +5530,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  		uint32_t mask;
  		if (conf & 0x1)
  			entry->lvdsconf.use_straps_for_mode = true;
@@ -1278,7 +1539,7 @@ index 0e9cd1d..4b0d67c 100644
  			mask = ~0xd;
  			/*
  			 * The laptop in bug 14567 lies and claims to not use
-@@ -5347,7 +5425,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5347,7 +5554,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  			 * Until we even try to use these on G8x, it's
  			 * useless reporting unknown bits.  They all are.
  			 */
@@ -1287,7 +1548,7 @@ index 0e9cd1d..4b0d67c 100644
  				break;
  
  			NV_ERROR(dev, "Unknown LVDS configuration bits, "
-@@ -5357,7 +5435,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5357,7 +5564,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  		}
  	case OUTPUT_TV:
  	{
@@ -1296,7 +1557,7 @@ index 0e9cd1d..4b0d67c 100644
  			entry->tvconf.has_component_output = conf & (0x8 << 4);
  		else
  			entry->tvconf.has_component_output = false;
-@@ -5384,8 +5462,10 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5384,8 +5591,10 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  		break;
  	case 0xe:
  		/* weird g80 mobile type that "nv" treats as a terminator */
@@ -1308,7 +1569,7 @@ index 0e9cd1d..4b0d67c 100644
  	}
  
  	/* unsure what DCB version introduces this, 3.0? */
-@@ -5396,7 +5476,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
+@@ -5396,7 +5605,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
  }
  
  static bool
@@ -1317,7 +1578,7 @@ index 0e9cd1d..4b0d67c 100644
  		  uint32_t conn, uint32_t conf, struct dcb_entry *entry)
  {
  	switch (conn & 0x0000000f) {
-@@ -5462,27 +5542,27 @@ parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb,
+@@ -5462,27 +5671,27 @@ parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb,
  	return true;
  }
  
@@ -1353,7 +1614,7 @@ index 0e9cd1d..4b0d67c 100644
  {
  	/*
  	 * DCB v2.0 lists each output combination separately.
-@@ -5534,8 +5614,7 @@ static int
+@@ -5534,8 +5743,7 @@ static int
  parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1363,7 +1624,7 @@ index 0e9cd1d..4b0d67c 100644
  	uint16_t dcbptr = 0, i2ctabptr = 0;
  	uint8_t *dcbtable;
  	uint8_t headerlen = 0x4, entries = DCB_MAX_NUM_ENTRIES;
-@@ -5543,9 +5622,6 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5543,9 +5751,6 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  	int recordlength = 8, confofs = 4;
  	int i;
  
@@ -1373,7 +1634,7 @@ index 0e9cd1d..4b0d67c 100644
  	/* get the offset from 0x36 */
  	if (dev_priv->card_type > NV_04) {
  		dcbptr = ROM16(bios->data[0x36]);
-@@ -5567,21 +5643,21 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5567,21 +5772,21 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  	dcbtable = &bios->data[dcbptr];
  
  	/* get DCB version */
@@ -1401,7 +1662,7 @@ index 0e9cd1d..4b0d67c 100644
  		} else {
  			i2ctabptr = ROM16(dcbtable[2]);
  			sig = ROM32(dcbtable[4]);
-@@ -5593,7 +5669,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5593,7 +5798,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  					"signature (%08X)\n", sig);
  			return -EINVAL;
  		}
@@ -1410,7 +1671,7 @@ index 0e9cd1d..4b0d67c 100644
  		char sig[8] = { 0 };
  
  		strncpy(sig, (char *)&dcbtable[-7], 7);
-@@ -5641,14 +5717,11 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5641,14 +5846,11 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  	if (!i2ctabptr)
  		NV_WARN(dev, "No pointer to DCB I2C port table\n");
  	else {
@@ -1428,7 +1689,7 @@ index 0e9cd1d..4b0d67c 100644
  	if (entries > DCB_MAX_NUM_ENTRIES)
  		entries = DCB_MAX_NUM_ENTRIES;
  
-@@ -5673,7 +5746,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5673,7 +5875,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  		NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n",
  			     dcb->entries, connection, config);
  
@@ -1437,7 +1698,7 @@ index 0e9cd1d..4b0d67c 100644
  			break;
  	}
  
-@@ -5681,18 +5754,22 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
+@@ -5681,18 +5883,22 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
  	 * apart for v2.1+ not being known for requiring merging, this
  	 * guarantees dcbent->index is the index of the entry in the rom image
  	 */
@@ -1465,7 +1726,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	/*
  	 * DCB 3.0 also has the table in most cases, but there are some cards
-@@ -5700,9 +5777,11 @@ fixup_legacy_connector(struct nvbios *bios)
+@@ -5700,9 +5906,11 @@ fixup_legacy_connector(struct nvbios *bios)
  	 * indices are all 0.  We don't need the connector indices on pre-G80
  	 * chips (yet?) so limit the use to DCB 4.0 and above.
  	 */
@@ -1478,7 +1739,7 @@ index 0e9cd1d..4b0d67c 100644
  	/*
  	 * No known connector info before v3.0, so make it up.  the rule here
  	 * is: anything on the same i2c bus is considered to be on the same
-@@ -5710,37 +5789,38 @@ fixup_legacy_connector(struct nvbios *bios)
+@@ -5710,37 +5918,38 @@ fixup_legacy_connector(struct nvbios *bios)
  	 * its own unique connector index.
  	 */
  	for (i = 0; i < dcb->entries; i++) {
@@ -1530,7 +1791,7 @@ index 0e9cd1d..4b0d67c 100644
  	int i;
  
  	for (i = 0; i < dcb->entries; i++) {
-@@ -5826,7 +5906,7 @@ static int load_nv17_hw_sequencer_ucode(struct drm_device *dev,
+@@ -5826,7 +6035,7 @@ static int load_nv17_hw_sequencer_ucode(struct drm_device *dev,
  uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1539,7 +1800,7 @@ index 0e9cd1d..4b0d67c 100644
  	const uint8_t edid_sig[] = {
  			0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
  	uint16_t offset = 0;
-@@ -5859,7 +5939,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
+@@ -5859,7 +6068,7 @@ 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;
@@ -1548,7 +1809,7 @@ index 0e9cd1d..4b0d67c 100644
  	struct init_exec iexec = { true, false };
  
  	mutex_lock(&bios->lock);
-@@ -5872,7 +5952,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
+@@ -5872,7 +6081,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
  static bool NVInitVBIOS(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1557,7 +1818,7 @@ index 0e9cd1d..4b0d67c 100644
  
  	memset(bios, 0, sizeof(struct nvbios));
  	mutex_init(&bios->lock);
-@@ -5888,7 +5968,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
+@@ -5888,7 +6097,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
  static int nouveau_parse_vbios_struct(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1566,7 +1827,7 @@ index 0e9cd1d..4b0d67c 100644
  	const uint8_t bit_signature[] = { 0xff, 0xb8, 'B', 'I', 'T' };
  	const uint8_t bmp_signature[] = { 0xff, 0x7f, 'N', 'V', 0x0 };
  	int offset;
-@@ -5915,7 +5995,7 @@ int
+@@ -5915,7 +6124,7 @@ int
  nouveau_run_vbios_init(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1575,7 +1836,7 @@ index 0e9cd1d..4b0d67c 100644
  	int i, ret = 0;
  
  	NVLockVgaCrtcs(dev, false);
-@@ -5946,9 +6026,9 @@ nouveau_run_vbios_init(struct drm_device *dev)
+@@ -5946,9 +6155,9 @@ nouveau_run_vbios_init(struct drm_device *dev)
  	}
  
  	if (dev_priv->card_type >= NV_50) {
@@ -1587,7 +1848,7 @@ index 0e9cd1d..4b0d67c 100644
  						       0, 0);
  		}
  	}
-@@ -5962,11 +6042,11 @@ static void
+@@ -5962,11 +6171,11 @@ static void
  nouveau_bios_i2c_devices_takedown(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1601,7 +1862,7 @@ index 0e9cd1d..4b0d67c 100644
  	for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++, entry++)
  		nouveau_i2c_fini(dev, entry);
  }
-@@ -5975,13 +6055,11 @@ int
+@@ -5975,13 +6184,11 @@ int
  nouveau_bios_init(struct drm_device *dev)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1616,7 +1877,7 @@ index 0e9cd1d..4b0d67c 100644
  	if (!NVInitVBIOS(dev))
  		return -ENODEV;
  
-@@ -6023,10 +6101,8 @@ nouveau_bios_init(struct drm_device *dev)
+@@ -6023,10 +6230,8 @@ nouveau_bios_init(struct drm_device *dev)
  	bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0);
  
  	ret = nouveau_run_vbios_init(dev);
@@ -1629,14 +1890,15 @@ index 0e9cd1d..4b0d67c 100644
  	/* feature_byte on BMP is poor, but init always sets CR4B */
  	was_locked = NVLockVgaCrtcs(dev, false);
 diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
-index fd94bd6..c0d7b0a 100644
+index fd94bd6..adf4ec2 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h
 +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
-@@ -34,9 +34,71 @@
+@@ -34,9 +34,72 @@
  
  #define DCB_LOC_ON_CHIP 0
  
 +struct dcb_i2c_entry {
++	uint32_t entry;
 +	uint8_t port_type;
 +	uint8_t read, write;
 +	struct nouveau_i2c_chan *chan;
@@ -1705,7 +1967,7 @@ index fd94bd6..c0d7b0a 100644
  	uint8_t i2c_index;
  	uint8_t heads;
  	uint8_t connector;
-@@ -71,69 +133,22 @@ struct dcb_entry {
+@@ -71,69 +134,22 @@ struct dcb_entry {
  	bool i2c_upper_default;
  };
  
@@ -1779,7 +2041,7 @@ index fd94bd6..c0d7b0a 100644
  enum nouveau_or {
  	OUTPUT_A = (1 << 0),
  	OUTPUT_B = (1 << 1),
-@@ -190,8 +205,8 @@ struct pll_lims {
+@@ -190,8 +206,8 @@ struct pll_lims {
  	int refclk;
  };
  
@@ -1790,7 +2052,7 @@ index fd94bd6..c0d7b0a 100644
  
  	uint8_t chip_version;
  
-@@ -199,11 +214,6 @@ struct nouveau_bios_info {
+@@ -199,11 +215,6 @@ struct nouveau_bios_info {
  	uint32_t tvdactestval;
  	uint8_t digital_min_front_porch;
  	bool fp_no_ddc;
@@ -1802,7 +2064,7 @@ index fd94bd6..c0d7b0a 100644
  
  	struct mutex lock;
  
-@@ -234,7 +244,7 @@ struct nvbios {
+@@ -234,7 +245,7 @@ struct nvbios {
  	uint16_t some_script_ptr; /* BIT I + 14 */
  	uint16_t init96_tbl_ptr; /* BIT I + 16 */
  
@@ -1811,7 +2073,7 @@ index fd94bd6..c0d7b0a 100644
  
  	struct {
  		int crtchead;
-@@ -260,7 +270,6 @@ struct nvbios {
+@@ -260,7 +271,6 @@ struct nvbios {
  		bool reset_after_pclk_change;
  		bool dual_link;
  		bool link_c_increment;
@@ -2484,7 +2746,7 @@ index da3b93b..60a709c 100644
  		struct nouveau_framebuffer *nouveau_fb;
  
 diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
-index 5be0cca..9e12c93 100644
+index 5be0cca..b908f77 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h
 +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
 @@ -76,6 +76,7 @@ struct nouveau_bo {
@@ -2647,7 +2909,7 @@ index 5be0cca..9e12c93 100644
  extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index);
  extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
  extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
-@@ -1163,6 +1166,10 @@ extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
+@@ -1163,6 +1166,16 @@ extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
  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);
  
@@ -2655,18 +2917,26 @@ index 5be0cca..9e12c93 100644
 +int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
 +int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
 +
++/* nv50_calc. */
++int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
++		  int *N1, int *M1, int *N2, int *M2, int *P);
++int nv50_calc_pll2(struct drm_device *, struct pll_lims *,
++		   int clk, int *N, int *fN, int *M, int *P);
++
  #ifndef ioread32_native
  #ifdef __BIG_ENDIAN
  #define ioread16_native ioread16be
 diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
-index bc4a240..9f28b94 100644
+index bc4a240..e1df820 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
 +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
-@@ -47,6 +47,7 @@ struct nouveau_encoder {
+@@ -47,6 +47,9 @@ struct nouveau_encoder {
  
  	union {
  		struct {
 +			int mc_unknown;
++			uint32_t unk0;
++			uint32_t unk1;
  			int dpcd_version;
  			int link_nr;
  			int link_bw;
@@ -2772,15 +3042,15 @@ index dc46792..7855b35 100644
  	if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
  	    cv >= 0x40) {
 diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
-index 70e994d..88583e7 100644
+index 70e994d..316a3c7 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
 +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
-@@ -254,16 +254,16 @@ struct nouveau_i2c_chan *
+@@ -254,16 +254,27 @@ struct nouveau_i2c_chan *
  nouveau_i2c_find(struct drm_device *dev, int index)
  {
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
 -	struct nvbios *bios = &dev_priv->VBIOS;
-+	struct nvbios *bios = &dev_priv->vbios;
++	struct dcb_i2c_entry *i2c = &dev_priv->vbios.dcb.i2c[index];
  
 -	if (index > DCB_MAX_NUM_I2C_ENTRIES)
 +	if (index >= DCB_MAX_NUM_I2C_ENTRIES)
@@ -2788,13 +3058,25 @@ index 70e994d..88583e7 100644
  
 -	if (!bios->bdcb.dcb.i2c[index].chan) {
 -		if (nouveau_i2c_init(dev, &bios->bdcb.dcb.i2c[index], index))
-+	if (!bios->dcb.i2c[index].chan) {
-+		if (nouveau_i2c_init(dev, &bios->dcb.i2c[index], index))
- 			return NULL;
+-			return NULL;
++	if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) {
++		uint32_t reg = 0xe500, val;
++
++		if (i2c->port_type == 6) {
++			reg += i2c->read * 0x50;
++			val  = 0x2002;
++		} else {
++			reg += ((i2c->entry & 0x1e00) >> 9) * 0x50;
++			val  = 0xe001;
++		}
++
++		nv_wr32(dev, reg, (nv_rd32(dev, reg) & ~0xf003) | val);
  	}
  
 -	return bios->bdcb.dcb.i2c[index].chan;
-+	return bios->dcb.i2c[index].chan;
++	if (!i2c->chan && nouveau_i2c_init(dev, i2c, index))
++		return NULL;
++	return i2c->chan;
  }
  
 diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -3684,6 +3966,18 @@ index 2dc09db..775a701 100644
  	/* remove reserved space at end of vram from available amount */
  	dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
  	dev_priv->fb_aper_free = dev_priv->fb_available_size;
+diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
+index aa9b310..6ca80a3 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
++++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
+@@ -826,6 +826,7 @@
+ #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2                          0x02000000
+ #define NV50_SOR_DP_UNK118(i,l)          (0x0061c118 + (i) * 0x800 + (l) * 0x80)
+ #define NV50_SOR_DP_UNK120(i,l)          (0x0061c120 + (i) * 0x800 + (l) * 0x80)
++#define NV50_SOR_DP_UNK128(i,l)          (0x0061c128 + (i) * 0x800 + (l) * 0x80)
+ #define NV50_SOR_DP_UNK130(i,l)          (0x0061c130 + (i) * 0x800 + (l) * 0x80)
+ 
+ #define NV50_PDISPLAY_USER(i)                        ((i) * 0x1000 + 0x00640000)
 diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
 index ed15905..554fb45 100644
 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -4083,6 +4377,164 @@ index 53e8afe..0616c96 100644
  	/* Turn all the tiling regions off. */
  	for (i = 0; i < pfb->num_tiles; i++)
  		nv40_graph_set_region_tiling(dev, i, 0, 0, 0);
+diff --git a/drivers/gpu/drm/nouveau/nv50_calc.c b/drivers/gpu/drm/nouveau/nv50_calc.c
+new file mode 100644
+index 0000000..90f3f6b
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nv50_calc.c
+@@ -0,0 +1,88 @@
++/*
++ * Copyright 2010 Red Hat Inc.
++ *
++ * 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 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 HOLDER(S) OR AUTHOR(S) 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.
++ *
++ * Authors: Ben Skeggs
++ */
++
++#include "drmP.h"
++#include "drm_fixed.h"
++#include "nouveau_drv.h"
++#include "nouveau_hw.h"
++
++int
++nv50_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
++	      int *N1, int *M1, int *N2, int *M2, int *P)
++{
++	struct nouveau_pll_vals pll_vals;
++	int ret;
++
++	ret = nouveau_calc_pll_mnp(dev, pll, clk, &pll_vals);
++	if (ret <= 0)
++		return ret;
++
++	*N1 = pll_vals.N1;
++	*M1 = pll_vals.M1;
++	*N2 = pll_vals.N2;
++	*M2 = pll_vals.M2;
++	*P = pll_vals.log2P;
++	return ret;
++}
++
++int
++nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
++	       int *N, int *fN, int *M, int *P)
++{
++	fixed20_12 fb_div, a, b;
++
++	*P = pll->vco1.maxfreq / clk;
++	if (*P > pll->max_p)
++		*P = pll->max_p;
++	if (*P < pll->min_p)
++		*P = pll->min_p;
++
++	/* *M = ceil(refclk / pll->vco.max_inputfreq); */
++	a.full = dfixed_const(pll->refclk);
++	b.full = dfixed_const(pll->vco1.max_inputfreq);
++	a.full = dfixed_div(a, b);
++	a.full = dfixed_ceil(a);
++	*M = dfixed_trunc(a);
++
++	/* fb_div = (vco * *M) / refclk; */
++	fb_div.full = dfixed_const(clk * *P);
++	fb_div.full = dfixed_mul(fb_div, a);
++	a.full = dfixed_const(pll->refclk);
++	fb_div.full = dfixed_div(fb_div, a);
++
++	/* *N = floor(fb_div); */
++	a.full = dfixed_floor(fb_div);
++	*N = dfixed_trunc(fb_div);
++
++	/* *fN = (fmod(fb_div, 1.0) * 8192) - 4096; */
++	b.full = dfixed_const(8192);
++	a.full = dfixed_mul(a, b);
++	fb_div.full = dfixed_mul(fb_div, b);
++	fb_div.full = fb_div.full - a.full;
++	*fN = dfixed_trunc(fb_div) - 4096;
++	*fN &= 0xffff;
++
++	return clk;
++}
++
+diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
+index d1a651e..03d0e41 100644
+--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
++++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
+@@ -264,32 +264,40 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update)
+ int
+ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
+ {
+-	uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
+-	struct nouveau_pll_vals pll;
+-	struct pll_lims limits;
++	uint32_t reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
++	struct pll_lims pll;
+ 	uint32_t reg1, reg2;
+-	int ret;
++	int ret, N1, M1, N2, M2, P;
+ 
+-	ret = get_pll_limits(dev, pll_reg, &limits);
++	ret = get_pll_limits(dev, reg, &pll);
+ 	if (ret)
+ 		return ret;
+ 
+-	ret = nouveau_calc_pll_mnp(dev, &limits, pclk, &pll);
+-	if (ret <= 0)
+-		return ret;
++	if (pll.vco2.maxfreq) {
++		ret = nv50_calc_pll(dev, &pll, pclk, &N1, &M1, &N2, &M2, &P);
++		if (ret <= 0)
++			return 0;
++
++		NV_DEBUG(dev, "pclk %d out %d NM1 %d %d NM2 %d %d P %d\n",
++			 pclk, ret, N1, M1, N2, M2, P);
+ 
+-	if (limits.vco2.maxfreq) {
+-		reg1 = nv_rd32(dev, pll_reg + 4) & 0xff00ff00;
+-		reg2 = nv_rd32(dev, pll_reg + 8) & 0x8000ff00;
+-		nv_wr32(dev, pll_reg, 0x10000611);
+-		nv_wr32(dev, pll_reg + 4, reg1 | (pll.M1 << 16) | pll.N1);
+-		nv_wr32(dev, pll_reg + 8,
+-			reg2 | (pll.log2P << 28) | (pll.M2 << 16) | pll.N2);
++		reg1 = nv_rd32(dev, reg + 4) & 0xff00ff00;
++		reg2 = nv_rd32(dev, reg + 8) & 0x8000ff00;
++		nv_wr32(dev, reg, 0x10000611);
++		nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1);
++		nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
+ 	} else {
+-		reg1 = nv_rd32(dev, pll_reg + 4) & 0xffc00000;
+-		nv_wr32(dev, pll_reg, 0x50000610);
+-		nv_wr32(dev, pll_reg + 4, reg1 |
+-			(pll.log2P << 16) | (pll.M1 << 8) | pll.N1);
++		ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
++		if (ret <= 0)
++			return 0;
++
++		NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
++			 pclk, ret, N1, N2, M1, P);
++
++		reg1 = nv_rd32(dev, reg + 4) & 0xffc00000;
++		nv_wr32(dev, reg, 0x50000610);
++		nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
++		nv_wr32(dev, reg + 8, N2);
+ 	}
+ 
+ 	return 0;
 diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
 index f08f042..1fd9537 100644
 --- a/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -4099,7 +4551,7 @@ index f08f042..1fd9537 100644
  			  load_pattern);
  	} else {
 diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
-index 90f0bf5..649db4c 100644
+index 90f0bf5..2c2ec5f 100644
 --- a/drivers/gpu/drm/nouveau/nv50_display.c
 +++ b/drivers/gpu/drm/nouveau/nv50_display.c
 @@ -143,7 +143,7 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
@@ -4227,7 +4679,54 @@ index 90f0bf5..649db4c 100644
  			if (bios->fp.dual_link)
  				script |= 0x0100;
  			if (bios->fp.if_is_24bit)
-@@ -919,10 +887,12 @@ nv50_display_error_handler(struct drm_device *dev)
+@@ -815,6 +783,37 @@ ack:
+ }
+ 
+ static void
++nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
++{
++	int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
++	struct drm_encoder *encoder;
++	uint32_t tmp, unk0 = 0, unk1 = 0;
++
++	if (dcb->type != OUTPUT_DP)
++		return;
++
++	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
++		struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
++
++		if (nv_encoder->dcb == dcb) {
++			unk0 = nv_encoder->dp.unk0;
++			unk1 = nv_encoder->dp.unk1;
++			break;
++		}
++	}
++
++	if (unk0 || unk1) {
++		tmp  = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
++		tmp &= 0xfffffe03;
++		nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp | unk0);
++
++		tmp  = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
++		tmp &= 0xfef080c0;
++		nv_wr32(dev, NV50_SOR_DP_UNK128(or, link), tmp | unk1);
++	}
++}
++
++static void
+ nv50_display_unk20_handler(struct drm_device *dev)
+ {
+ 	struct dcb_entry *dcbent;
+@@ -837,6 +836,8 @@ nv50_display_unk20_handler(struct drm_device *dev)
+ 
+ 	nouveau_bios_run_display_table(dev, dcbent, script, pclk);
+ 
++	nv50_display_unk20_dp_hack(dev, dcbent);
++
+ 	tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
+ 	tmp &= ~0x000000f;
+ 	nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp);
+@@ -919,10 +920,12 @@ nv50_display_error_handler(struct drm_device *dev)
  	nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR, 0x90000000);
  }
  
@@ -4243,7 +4742,16 @@ index 90f0bf5..649db4c 100644
  	struct drm_connector *connector;
  	const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
  	uint32_t unplug_mask, plug_mask, change_mask;
-@@ -983,8 +953,10 @@ nv50_display_irq_handler(struct drm_device *dev)
+@@ -975,6 +978,8 @@ nv50_display_irq_hotplug(struct drm_device *dev)
+ 	nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
+ 	if (dev_priv->chipset >= 0x90)
+ 		nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
++
++	drm_sysfs_hotplug_event(dev);
+ }
+ 
+ void
+@@ -983,8 +988,10 @@ nv50_display_irq_handler(struct drm_device *dev)
  	struct drm_nouveau_private *dev_priv = dev->dev_private;
  	uint32_t delayed = 0;
  
@@ -7102,7 +7610,7 @@ index f0dc4e3..5f21df3 100644
  		return -EINVAL;
  
 diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
-index c2fff54..0c68698 100644
+index c2fff54..b11eaf9 100644
 --- a/drivers/gpu/drm/nouveau/nv50_sor.c
 +++ b/drivers/gpu/drm/nouveau/nv50_sor.c
 @@ -211,7 +211,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
@@ -7122,23 +7630,28 @@ index c2fff54..0c68698 100644
  	struct nouveau_encoder *nv_encoder = NULL;
  	struct drm_encoder *encoder;
  	bool dum;
-@@ -319,5 +320,27 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
+@@ -319,5 +320,32 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
  	encoder->possible_crtcs = entry->heads;
  	encoder->possible_clones = 0;
  
 +	if (nv_encoder->dcb->type == OUTPUT_DP) {
-+		uint32_t mc, or = nv_encoder->or;
++		int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1);
++		uint32_t tmp;
 +
 +		if (dev_priv->chipset < 0x90 ||
 +		    dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0)
-+			mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or));
++			tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or));
 +		else
-+			mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or));
++			tmp = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or));
 +
-+		switch ((mc & 0x00000f00) >> 8) {
++		switch ((tmp & 0x00000f00) >> 8) {
 +		case 8:
 +		case 9:
-+			nv_encoder->dp.mc_unknown = (mc & 0x000f0000) >> 16;
++			nv_encoder->dp.mc_unknown = (tmp & 0x000f0000) >> 16;
++			tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
++			nv_encoder->dp.unk0 = tmp & 0x000001fc;
++			tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
++			nv_encoder->dp.unk1 = tmp & 0x010f7f3f;
 +			break;
 +		default:
 +			break;


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-13/kernel.spec,v
retrieving revision 1.2008
retrieving revision 1.2009
diff -u -p -r1.2008 -r1.2009
--- kernel.spec	28 Apr 2010 15:15:48 -0000	1.2008
+++ kernel.spec	29 Apr 2010 01:06:41 -0000	1.2009
@@ -734,6 +734,7 @@ Patch1815: drm-nouveau-abi16.patch
 Patch1816: drm-nouveau-updates.patch
 # requires code that hasn't been merged upstream yet
 Patch1817: drm-nouveau-acpi-edid-fallback.patch
+Patch1818: drm-nouveau-drm-fixed-header.patch
 
 # drm fixes
 Patch1819: drm-intel-big-hammer.patch
@@ -1440,6 +1441,7 @@ ApplyPatch drm-radeon-ss-fix.patch
 ApplyPatch drm-nouveau-abi16.patch
 ApplyPatch drm-nouveau-updates.patch
 ApplyPatch drm-nouveau-acpi-edid-fallback.patch
+ApplyPatch drm-nouveau-drm-fixed-header.patch
 # pm broken on my thinkpad t60p - airlied
 ApplyPatch drm-intel-big-hammer.patch
 ApplyOptionalPatch drm-intel-next.patch
@@ -2166,6 +2168,12 @@ fi
 # and build.
 
 %changelog
+* Thu Apr 29 2010 Ben Skeggs <bskeggs at redhat.com> 2.6.33.3-73
+- nouveau: initial eDP support + DP suspend/resume fixes
+- nouveau: fix monitor detection on certain chipsets with DP support
+- nouveau: better CRTC PLL calculation on latest chipsets
+- nouveau: send hotplug events down to userspace
+
 * Wed Apr 28 2010 John W. Linville <linville at redhat.com> 2.6.33.3-72
 - Revert "ath9k: fix lockdep warning when unloading module"
 



More information about the scm-commits mailing list