diff options
Diffstat (limited to 'drm-nouveau-updates.patch')
-rw-r--r-- | drm-nouveau-updates.patch | 6997 |
1 files changed, 6997 insertions, 0 deletions
diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch new file mode 100644 index 000000000..1b704ff0a --- /dev/null +++ b/drm-nouveau-updates.patch @@ -0,0 +1,6997 @@ + drivers/gpu/drm/drm_crtc_helper.c | 22 +- + drivers/gpu/drm/i2c/ch7006_drv.c | 22 +- + drivers/gpu/drm/i2c/ch7006_priv.h | 2 +- + drivers/gpu/drm/nouveau/Makefile | 2 +- + drivers/gpu/drm/nouveau/nouveau_acpi.c | 38 ++- + drivers/gpu/drm/nouveau/nouveau_bios.c | 636 +++++++++++++++++++++------ + drivers/gpu/drm/nouveau/nouveau_bios.h | 4 +- + drivers/gpu/drm/nouveau/nouveau_bo.c | 9 +- + drivers/gpu/drm/nouveau/nouveau_calc.c | 4 +- + drivers/gpu/drm/nouveau/nouveau_channel.c | 5 - + drivers/gpu/drm/nouveau/nouveau_connector.c | 404 ++++++++---------- + drivers/gpu/drm/nouveau/nouveau_connector.h | 7 +- + drivers/gpu/drm/nouveau/nouveau_dma.c | 8 +- + drivers/gpu/drm/nouveau/nouveau_dp.c | 24 +- + drivers/gpu/drm/nouveau/nouveau_drv.c | 31 +- + drivers/gpu/drm/nouveau/nouveau_drv.h | 90 ++--- + drivers/gpu/drm/nouveau/nouveau_encoder.h | 10 +- + drivers/gpu/drm/nouveau/nouveau_fbcon.c | 2 +- + drivers/gpu/drm/nouveau/nouveau_fence.c | 31 +- + drivers/gpu/drm/nouveau/nouveau_gem.c | 11 +- + drivers/gpu/drm/nouveau/nouveau_grctx.c | 160 ------- + drivers/gpu/drm/nouveau/nouveau_i2c.c | 34 ++ + drivers/gpu/drm/nouveau/nouveau_i2c.h | 3 + + drivers/gpu/drm/nouveau/nouveau_mem.c | 275 ++---------- + drivers/gpu/drm/nouveau/nouveau_notifier.c | 30 +- + drivers/gpu/drm/nouveau/nouveau_object.c | 105 ++--- + drivers/gpu/drm/nouveau/nouveau_reg.h | 91 +++-- + drivers/gpu/drm/nouveau/nouveau_sgdma.c | 46 +-- + drivers/gpu/drm/nouveau/nouveau_state.c | 172 +++----- + drivers/gpu/drm/nouveau/nv04_crtc.c | 5 + + drivers/gpu/drm/nouveau/nv04_dac.c | 37 ++- + drivers/gpu/drm/nouveau/nv04_dfp.c | 12 +- + drivers/gpu/drm/nouveau/nv04_display.c | 64 ++-- + drivers/gpu/drm/nouveau/nv04_fifo.c | 20 +- + drivers/gpu/drm/nouveau/nv04_graph.c | 5 +- + drivers/gpu/drm/nouveau/nv04_instmem.c | 21 +- + drivers/gpu/drm/nouveau/nv04_mc.c | 4 + + drivers/gpu/drm/nouveau/nv04_tv.c | 125 ++---- + drivers/gpu/drm/nouveau/nv10_fifo.c | 10 - + drivers/gpu/drm/nouveau/nv17_tv.c | 46 ++- + drivers/gpu/drm/nouveau/nv20_graph.c | 96 +++-- + drivers/gpu/drm/nouveau/nv40_fifo.c | 8 - + drivers/gpu/drm/nouveau/nv40_graph.c | 58 +-- + drivers/gpu/drm/nouveau/nv40_mc.c | 2 +- + drivers/gpu/drm/nouveau/nv50_crtc.c | 42 +-- + drivers/gpu/drm/nouveau/nv50_dac.c | 43 ++- + drivers/gpu/drm/nouveau/nv50_display.c | 385 ++++++++++------- + drivers/gpu/drm/nouveau/nv50_fifo.c | 126 ++---- + drivers/gpu/drm/nouveau/nv50_graph.c | 86 ++--- + drivers/gpu/drm/nouveau/nv50_instmem.c | 67 +-- + drivers/gpu/drm/nouveau/nv50_sor.c | 105 +++--- + drivers/gpu/drm/nouveau/nvreg.h | 22 - + 52 files changed, 1748 insertions(+), 1919 deletions(-) + +diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c +index 9b2a541..1eaa315 100644 +--- a/drivers/gpu/drm/drm_crtc_helper.c ++++ b/drivers/gpu/drm/drm_crtc_helper.c +@@ -201,6 +201,17 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) + } + EXPORT_SYMBOL(drm_helper_crtc_in_use); + ++static void ++drm_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; ++ ++ if (encoder_funcs->disable) ++ (*encoder_funcs->disable)(encoder); ++ else ++ (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); ++} ++ + /** + * drm_helper_disable_unused_functions - disable unused objects + * @dev: DRM device +@@ -215,7 +226,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) + { + struct drm_encoder *encoder; + struct drm_connector *connector; +- struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_crtc *crtc; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { +@@ -226,12 +236,8 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { +- encoder_funcs = encoder->helper_private; + if (!drm_helper_encoder_in_use(encoder)) { +- if (encoder_funcs->disable) +- (*encoder_funcs->disable)(encoder); +- else +- (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); ++ drm_encoder_disable(encoder); + /* disconnector encoder from any connector */ + encoder->crtc = NULL; + } +@@ -292,11 +298,11 @@ drm_crtc_prepare_encoders(struct drm_device *dev) + encoder_funcs = encoder->helper_private; + /* Disable unused encoders */ + if (encoder->crtc == NULL) +- (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); ++ drm_encoder_disable(encoder); + /* Disable encoders whose CRTC is about to change */ + if (encoder_funcs->get_crtc && + encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) +- (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); ++ drm_encoder_disable(encoder); + } + } + +diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c +index 81681a0..833b35f 100644 +--- a/drivers/gpu/drm/i2c/ch7006_drv.c ++++ b/drivers/gpu/drm/i2c/ch7006_drv.c +@@ -33,7 +33,7 @@ static void ch7006_encoder_set_config(struct drm_encoder *encoder, + { + struct ch7006_priv *priv = to_ch7006_priv(encoder); + +- priv->params = params; ++ priv->params = *(struct ch7006_encoder_params *)params; + } + + static void ch7006_encoder_destroy(struct drm_encoder *encoder) +@@ -114,7 +114,7 @@ static void ch7006_encoder_mode_set(struct drm_encoder *encoder, + { + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + struct ch7006_priv *priv = to_ch7006_priv(encoder); +- struct ch7006_encoder_params *params = priv->params; ++ struct ch7006_encoder_params *params = &priv->params; + struct ch7006_state *state = &priv->state; + uint8_t *regs = state->regs; + struct ch7006_mode *mode = priv->mode; +@@ -428,6 +428,22 @@ static int ch7006_remove(struct i2c_client *client) + return 0; + } + ++static int ch7006_suspend(struct i2c_client *client, pm_message_t mesg) ++{ ++ ch7006_dbg(client, "\n"); ++ ++ return 0; ++} ++ ++static int ch7006_resume(struct i2c_client *client) ++{ ++ ch7006_dbg(client, "\n"); ++ ++ ch7006_write(client, 0x3d, 0x0); ++ ++ return 0; ++} ++ + static int ch7006_encoder_init(struct i2c_client *client, + struct drm_device *dev, + struct drm_encoder_slave *encoder) +@@ -487,6 +503,8 @@ static struct drm_i2c_encoder_driver ch7006_driver = { + .i2c_driver = { + .probe = ch7006_probe, + .remove = ch7006_remove, ++ .suspend = ch7006_suspend, ++ .resume = ch7006_resume, + + .driver = { + .name = "ch7006", +diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h +index b06d3d9..1c6d2e3 100644 +--- a/drivers/gpu/drm/i2c/ch7006_priv.h ++++ b/drivers/gpu/drm/i2c/ch7006_priv.h +@@ -77,7 +77,7 @@ struct ch7006_state { + }; + + struct ch7006_priv { +- struct ch7006_encoder_params *params; ++ struct ch7006_encoder_params params; + struct ch7006_mode *mode; + + struct ch7006_state state; +diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile +index acd31ed..4a1db73 100644 +--- a/drivers/gpu/drm/nouveau/Makefile ++++ b/drivers/gpu/drm/nouveau/Makefile +@@ -9,7 +9,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ + nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \ + nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \ + nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ +- nouveau_dp.o nouveau_grctx.o \ ++ nouveau_dp.o \ + nv04_timer.o \ + nv04_mc.o nv40_mc.o nv50_mc.o \ + nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \ +diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c +index d4bcca8..c17a055 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c ++++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c +@@ -3,6 +3,7 @@ + #include <linux/slab.h> + #include <acpi/acpi_drivers.h> + #include <acpi/acpi_bus.h> ++#include <acpi/video.h> + + #include "drmP.h" + #include "drm.h" +@@ -11,6 +12,7 @@ + #include "nouveau_drv.h" + #include "nouveau_drm.h" + #include "nv50_display.h" ++#include "nouveau_connector.h" + + #include <linux/vga_switcheroo.h> + +@@ -42,7 +44,7 @@ static const char nouveau_dsm_muid[] = { + 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4, + }; + +-static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result) ++static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) + { + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_object_list input; +@@ -259,3 +261,37 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) + { + return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len); + } ++ ++int ++nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) ++{ ++ struct nouveau_connector *nv_connector = nouveau_connector(connector); ++ struct acpi_device *acpidev; ++ acpi_handle handle; ++ int type, ret; ++ void *edid; ++ ++ switch (connector->connector_type) { ++ case DRM_MODE_CONNECTOR_LVDS: ++ case DRM_MODE_CONNECTOR_eDP: ++ type = ACPI_VIDEO_DISPLAY_LCD; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev); ++ if (!handle) ++ return -ENODEV; ++ ++ ret = acpi_bus_get_device(handle, &acpidev); ++ if (ret) ++ return -ENODEV; ++ ++ ret = acpi_video_get_edid(acpidev, type, -1, &edid); ++ if (ret < 0) ++ return ret; ++ ++ nv_connector->edid = edid; ++ return 0; ++} +diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c +index e492919..aae29cc 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bios.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bios.c +@@ -28,6 +28,8 @@ + #include "nouveau_hw.h" + #include "nouveau_encoder.h" + ++#include <linux/io-mapping.h> ++ + /* these defines are made up */ + #define NV_CIO_CRE_44_HEADA 0x0 + #define NV_CIO_CRE_44_HEADB 0x3 +@@ -209,20 +211,20 @@ static struct methods shadow_methods[] = { + { "PCIROM", load_vbios_pci, true }, + { "ACPI", load_vbios_acpi, true }, + }; ++#define NUM_SHADOW_METHODS ARRAY_SIZE(shadow_methods) + + static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) + { +- const int nr_methods = ARRAY_SIZE(shadow_methods); + struct methods *methods = shadow_methods; + int testscore = 3; +- int scores[nr_methods], i; ++ int scores[NUM_SHADOW_METHODS], i; + + if (nouveau_vbios) { +- for (i = 0; i < nr_methods; i++) ++ for (i = 0; i < NUM_SHADOW_METHODS; i++) + if (!strcasecmp(nouveau_vbios, methods[i].desc)) + break; + +- if (i < nr_methods) { ++ if (i < NUM_SHADOW_METHODS) { + NV_INFO(dev, "Attempting to use BIOS image from %s\n", + methods[i].desc); + +@@ -234,7 +236,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) + NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios); + } + +- for (i = 0; i < nr_methods; i++) { ++ for (i = 0; i < NUM_SHADOW_METHODS; i++) { + NV_TRACE(dev, "Attempting to load BIOS image from %s\n", + methods[i].desc); + data[0] = data[1] = 0; /* avoid reuse of previous image */ +@@ -245,7 +247,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) + } + + while (--testscore > 0) { +- for (i = 0; i < nr_methods; i++) { ++ for (i = 0; i < NUM_SHADOW_METHODS; i++) { + if (scores[i] == testscore) { + NV_TRACE(dev, "Using BIOS image from %s\n", + methods[i].desc); +@@ -920,7 +922,7 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset, + NV_ERROR(bios->dev, + "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n", + offset, config, count); +- return -EINVAL; ++ return len; + } + + configval = ROM32(bios->data[offset + 11 + config * 4]); +@@ -1022,7 +1024,7 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset, + NV_ERROR(bios->dev, + "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n", + offset, config, count); +- return -EINVAL; ++ return len; + } + + freq = ROM16(bios->data[offset + 12 + config * 2]); +@@ -1194,7 +1196,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + dpe = nouveau_bios_dp_table(dev, dcb, &dummy); + if (!dpe) { + NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset); +- return -EINVAL; ++ return 3; + } + + switch (cond) { +@@ -1218,12 +1220,16 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + int ret; + + auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index); +- if (!auxch) +- return -ENODEV; ++ if (!auxch) { ++ NV_ERROR(dev, "0x%04X: couldn't get auxch\n", offset); ++ return 3; ++ } + + ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1); +- if (ret) +- return ret; ++ if (ret) { ++ NV_ERROR(dev, "0x%04X: auxch rd fail: %d\n", offset, ret); ++ return 3; ++ } + + if (cond & 1) + iexec->execute = false; +@@ -1392,7 +1398,7 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset, + NV_ERROR(bios->dev, + "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n", + offset, config, count); +- return -EINVAL; ++ return len; + } + + freq = ROM32(bios->data[offset + 11 + config * 4]); +@@ -1452,6 +1458,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + * "mask n" and OR it with "data n" before writing it back to the device + */ + ++ struct drm_device *dev = bios->dev; + uint8_t i2c_index = bios->data[offset + 1]; + uint8_t i2c_address = bios->data[offset + 2] >> 1; + uint8_t count = bios->data[offset + 3]; +@@ -1466,9 +1473,11 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + "Count: 0x%02X\n", + offset, i2c_index, i2c_address, count); + +- chan = init_i2c_device_find(bios->dev, i2c_index); +- if (!chan) +- return -ENODEV; ++ chan = init_i2c_device_find(dev, i2c_index); ++ if (!chan) { ++ NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset); ++ return len; ++ } + + for (i = 0; i < count; i++) { + uint8_t reg = bios->data[offset + 4 + i * 3]; +@@ -1479,8 +1488,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0, + I2C_SMBUS_READ, reg, + I2C_SMBUS_BYTE_DATA, &val); +- if (ret < 0) +- return ret; ++ if (ret < 0) { ++ NV_ERROR(dev, "0x%04X: i2c rd fail: %d\n", offset, ret); ++ return len; ++ } + + BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, " + "Mask: 0x%02X, Data: 0x%02X\n", +@@ -1494,8 +1505,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0, + I2C_SMBUS_WRITE, reg, + I2C_SMBUS_BYTE_DATA, &val); +- if (ret < 0) +- return ret; ++ if (ret < 0) { ++ NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret); ++ return len; ++ } + } + + return len; +@@ -1520,6 +1533,7 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + * "DCB I2C table entry index", set the register to "data n" + */ + ++ struct drm_device *dev = bios->dev; + uint8_t i2c_index = bios->data[offset + 1]; + uint8_t i2c_address = bios->data[offset + 2] >> 1; + uint8_t count = bios->data[offset + 3]; +@@ -1534,9 +1548,11 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + "Count: 0x%02X\n", + offset, i2c_index, i2c_address, count); + +- chan = init_i2c_device_find(bios->dev, i2c_index); +- if (!chan) +- return -ENODEV; ++ chan = init_i2c_device_find(dev, i2c_index); ++ if (!chan) { ++ NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset); ++ return len; ++ } + + for (i = 0; i < count; i++) { + uint8_t reg = bios->data[offset + 4 + i * 2]; +@@ -1553,8 +1569,10 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0, + I2C_SMBUS_WRITE, reg, + I2C_SMBUS_BYTE_DATA, &val); +- if (ret < 0) +- return ret; ++ if (ret < 0) { ++ NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret); ++ return len; ++ } + } + + return len; +@@ -1577,6 +1595,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + * address" on the I2C bus given by "DCB I2C table entry index" + */ + ++ struct drm_device *dev = bios->dev; + uint8_t i2c_index = bios->data[offset + 1]; + uint8_t i2c_address = bios->data[offset + 2] >> 1; + uint8_t count = bios->data[offset + 3]; +@@ -1584,7 +1603,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + struct nouveau_i2c_chan *chan; + struct i2c_msg msg; + uint8_t data[256]; +- int i; ++ int ret, i; + + if (!iexec->execute) + return len; +@@ -1593,9 +1612,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + "Count: 0x%02X\n", + offset, i2c_index, i2c_address, count); + +- chan = init_i2c_device_find(bios->dev, i2c_index); +- if (!chan) +- return -ENODEV; ++ chan = init_i2c_device_find(dev, i2c_index); ++ if (!chan) { ++ NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset); ++ return len; ++ } + + for (i = 0; i < count; i++) { + data[i] = bios->data[offset + 4 + i]; +@@ -1608,8 +1629,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + msg.flags = 0; + msg.len = count; + msg.buf = data; +- if (i2c_transfer(&chan->adapter, &msg, 1) != 1) +- return -EIO; ++ ret = i2c_transfer(&chan->adapter, &msg, 1); ++ if (ret != 1) { ++ NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret); ++ return len; ++ } + } + + return len; +@@ -1633,6 +1657,7 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + * used -- see get_tmds_index_reg() + */ + ++ struct drm_device *dev = bios->dev; + uint8_t mlv = bios->data[offset + 1]; + uint32_t tmdsaddr = bios->data[offset + 2]; + uint8_t mask = bios->data[offset + 3]; +@@ -1647,8 +1672,10 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + offset, mlv, tmdsaddr, mask, data); + + reg = get_tmds_index_reg(bios->dev, mlv); +- if (!reg) +- return -EINVAL; ++ if (!reg) { ++ NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset); ++ return 5; ++ } + + bios_wr32(bios, reg, + tmdsaddr | NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE); +@@ -1678,6 +1705,7 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset, + * register is used -- see get_tmds_index_reg() + */ + ++ struct drm_device *dev = bios->dev; + uint8_t mlv = bios->data[offset + 1]; + uint8_t count = bios->data[offset + 2]; + int len = 3 + count * 2; +@@ -1691,8 +1719,10 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset, + offset, mlv, count); + + reg = get_tmds_index_reg(bios->dev, mlv); +- if (!reg) +- return -EINVAL; ++ if (!reg) { ++ NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset); ++ return len; ++ } + + for (i = 0; i < count; i++) { + uint8_t tmdsaddr = bios->data[offset + 3 + i * 2]; +@@ -2039,6 +2069,323 @@ init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + return 5; + } + ++static inline void ++bios_md32(struct nvbios *bios, uint32_t reg, ++ uint32_t mask, uint32_t val) ++{ ++ bios_wr32(bios, reg, (bios_rd32(bios, reg) & ~mask) | val); ++} ++ ++static uint32_t ++peek_fb(struct drm_device *dev, struct io_mapping *fb, ++ uint32_t off) ++{ ++ uint32_t val = 0; ++ ++ if (off < pci_resource_len(dev->pdev, 1)) { ++ uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off); ++ ++ val = ioread32(p); ++ ++ io_mapping_unmap_atomic(p); ++ } ++ ++ return val; ++} ++ ++static void ++poke_fb(struct drm_device *dev, struct io_mapping *fb, ++ uint32_t off, uint32_t val) ++{ ++ if (off < pci_resource_len(dev->pdev, 1)) { ++ uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off); ++ ++ iowrite32(val, p); ++ wmb(); ++ ++ io_mapping_unmap_atomic(p); ++ } ++} ++ ++static inline bool ++read_back_fb(struct drm_device *dev, struct io_mapping *fb, ++ uint32_t off, uint32_t val) ++{ ++ poke_fb(dev, fb, off, val); ++ return val == peek_fb(dev, fb, off); ++} ++ ++static int ++nv04_init_compute_mem(struct nvbios *bios) ++{ ++ struct drm_device *dev = bios->dev; ++ uint32_t patt = 0xdeadbeef; ++ struct io_mapping *fb; ++ int i; ++ ++ /* Map the framebuffer aperture */ ++ fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1), ++ pci_resource_len(dev->pdev, 1)); ++ if (!fb) ++ return -ENOMEM; ++ ++ /* Sequencer and refresh off */ ++ NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) | 0x20); ++ bios_md32(bios, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); ++ ++ bios_md32(bios, NV04_PFB_BOOT_0, ~0, ++ NV04_PFB_BOOT_0_RAM_AMOUNT_16MB | ++ NV04_PFB_BOOT_0_RAM_WIDTH_128 | ++ NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT); ++ ++ for (i = 0; i < 4; i++) ++ poke_fb(dev, fb, 4 * i, patt); ++ ++ poke_fb(dev, fb, 0x400000, patt + 1); ++ ++ if (peek_fb(dev, fb, 0) == patt + 1) { ++ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, ++ NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT); ++ bios_md32(bios, NV04_PFB_DEBUG_0, ++ NV04_PFB_DEBUG_0_REFRESH_OFF, 0); ++ ++ for (i = 0; i < 4; i++) ++ poke_fb(dev, fb, 4 * i, patt); ++ ++ if ((peek_fb(dev, fb, 0xc) & 0xffff) != (patt & 0xffff)) ++ bios_md32(bios, NV04_PFB_BOOT_0, ++ NV04_PFB_BOOT_0_RAM_WIDTH_128 | ++ NV04_PFB_BOOT_0_RAM_AMOUNT, ++ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); ++ ++ } else if ((peek_fb(dev, fb, 0xc) & 0xffff0000) != ++ (patt & 0xffff0000)) { ++ bios_md32(bios, NV04_PFB_BOOT_0, ++ NV04_PFB_BOOT_0_RAM_WIDTH_128 | ++ NV04_PFB_BOOT_0_RAM_AMOUNT, ++ NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); ++ ++ } else if (peek_fb(dev, fb, 0) == patt) { ++ if (read_back_fb(dev, fb, 0x800000, patt)) ++ bios_md32(bios, NV04_PFB_BOOT_0, ++ NV04_PFB_BOOT_0_RAM_AMOUNT, ++ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); ++ else ++ bios_md32(bios, NV04_PFB_BOOT_0, ++ NV04_PFB_BOOT_0_RAM_AMOUNT, ++ NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); ++ ++ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, ++ NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT); ++ ++ } else if (!read_back_fb(dev, fb, 0x800000, patt)) { ++ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, ++ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); ++ ++ } ++ ++ /* Refresh on, sequencer on */ ++ bios_md32(bios, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); ++ NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) & ~0x20); ++ ++ io_mapping_free(fb); ++ return 0; ++} ++ ++static const uint8_t * ++nv05_memory_config(struct nvbios *bios) ++{ ++ /* Defaults for BIOSes lacking a memory config table */ ++ static const uint8_t default_config_tab[][2] = { ++ { 0x24, 0x00 }, ++ { 0x28, 0x00 }, ++ { 0x24, 0x01 }, ++ { 0x1f, 0x00 }, ++ { 0x0f, 0x00 }, ++ { 0x17, 0x00 }, ++ { 0x06, 0x00 }, ++ { 0x00, 0x00 } ++ }; ++ int i = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) & ++ NV_PEXTDEV_BOOT_0_RAMCFG) >> 2; ++ ++ if (bios->legacy.mem_init_tbl_ptr) ++ return &bios->data[bios->legacy.mem_init_tbl_ptr + 2 * i]; ++ else ++ return default_config_tab[i]; ++} ++ ++static int ++nv05_init_compute_mem(struct nvbios *bios) ++{ ++ struct drm_device *dev = bios->dev; ++ const uint8_t *ramcfg = nv05_memory_config(bios); ++ uint32_t patt = 0xdeadbeef; ++ struct io_mapping *fb; ++ int i, v; ++ ++ /* Map the framebuffer aperture */ ++ fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1), ++ pci_resource_len(dev->pdev, 1)); ++ if (!fb) ++ return -ENOMEM; ++ ++ /* Sequencer off */ ++ NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) | 0x20); ++ ++ if (bios_rd32(bios, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) ++ goto out; ++ ++ bios_md32(bios, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); ++ ++ /* If present load the hardcoded scrambling table */ ++ if (bios->legacy.mem_init_tbl_ptr) { ++ uint32_t *scramble_tab = (uint32_t *)&bios->data[ ++ bios->legacy.mem_init_tbl_ptr + 0x10]; ++ ++ for (i = 0; i < 8; i++) ++ bios_wr32(bios, NV04_PFB_SCRAMBLE(i), ++ ROM32(scramble_tab[i])); ++ } ++ ++ /* Set memory type/width/length defaults depending on the straps */ ++ bios_md32(bios, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); ++ ++ if (ramcfg[1] & 0x80) ++ bios_md32(bios, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); ++ ++ bios_md32(bios, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); ++ bios_md32(bios, NV04_PFB_CFG1, 0, 1); ++ ++ /* Probe memory bus width */ ++ for (i = 0; i < 4; i++) ++ poke_fb(dev, fb, 4 * i, patt); ++ ++ if (peek_fb(dev, fb, 0xc) != patt) ++ bios_md32(bios, NV04_PFB_BOOT_0, ++ NV04_PFB_BOOT_0_RAM_WIDTH_128, 0); ++ ++ /* Probe memory length */ ++ v = bios_rd32(bios, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; ++ ++ if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB && ++ (!read_back_fb(dev, fb, 0x1000000, ++patt) || ++ !read_back_fb(dev, fb, 0, ++patt))) ++ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, ++ NV04_PFB_BOOT_0_RAM_AMOUNT_16MB); ++ ++ if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB && ++ !read_back_fb(dev, fb, 0x800000, ++patt)) ++ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, ++ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); ++ ++ if (!read_back_fb(dev, fb, 0x400000, ++patt)) ++ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, ++ NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); ++ ++out: ++ /* Sequencer on */ ++ NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) & ~0x20); ++ ++ io_mapping_free(fb); ++ return 0; ++} ++ ++static int ++nv10_init_compute_mem(struct nvbios *bios) ++{ ++ struct drm_device *dev = bios->dev; ++ struct drm_nouveau_private *dev_priv = bios->dev->dev_private; ++ const int mem_width[] = { 0x10, 0x00, 0x20 }; ++ const int mem_width_count = (dev_priv->chipset >= 0x17 ? 3 : 2); ++ uint32_t patt = 0xdeadbeef; ++ struct io_mapping *fb; ++ int i, j, k; ++ ++ /* Map the framebuffer aperture */ ++ fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1), ++ pci_resource_len(dev->pdev, 1)); ++ if (!fb) ++ return -ENOMEM; ++ ++ bios_wr32(bios, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); ++ ++ /* Probe memory bus width */ ++ for (i = 0; i < mem_width_count; i++) { ++ bios_md32(bios, NV04_PFB_CFG0, 0x30, mem_width[i]); ++ ++ for (j = 0; j < 4; j++) { ++ for (k = 0; k < 4; k++) ++ poke_fb(dev, fb, 0x1c, 0); ++ ++ poke_fb(dev, fb, 0x1c, patt); ++ poke_fb(dev, fb, 0x3c, 0); ++ ++ if (peek_fb(dev, fb, 0x1c) == patt) ++ goto mem_width_found; ++ } ++ } ++ ++mem_width_found: ++ patt <<= 1; ++ ++ /* Probe amount of installed memory */ ++ for (i = 0; i < 4; i++) { ++ int off = bios_rd32(bios, NV04_PFB_FIFO_DATA) - 0x100000; ++ ++ poke_fb(dev, fb, off, patt); ++ poke_fb(dev, fb, 0, 0); ++ ++ peek_fb(dev, fb, 0); ++ peek_fb(dev, fb, 0); ++ peek_fb(dev, fb, 0); ++ peek_fb(dev, fb, 0); ++ ++ if (peek_fb(dev, fb, off) == patt) ++ goto amount_found; ++ } ++ ++ /* IC missing - disable the upper half memory space. */ ++ bios_md32(bios, NV04_PFB_CFG0, 0x1000, 0); ++ ++amount_found: ++ io_mapping_free(fb); ++ return 0; ++} ++ ++static int ++nv20_init_compute_mem(struct nvbios *bios) ++{ ++ struct drm_device *dev = bios->dev; ++ struct drm_nouveau_private *dev_priv = bios->dev->dev_private; ++ uint32_t mask = (dev_priv->chipset >= 0x25 ? 0x300 : 0x900); ++ uint32_t amount, off; ++ struct io_mapping *fb; ++ ++ /* Map the framebuffer aperture */ ++ fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1), ++ pci_resource_len(dev->pdev, 1)); ++ if (!fb) ++ return -ENOMEM; ++ ++ bios_wr32(bios, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); ++ ++ /* Allow full addressing */ ++ bios_md32(bios, NV04_PFB_CFG0, 0, mask); ++ ++ amount = bios_rd32(bios, NV04_PFB_FIFO_DATA); ++ for (off = amount; off > 0x2000000; off -= 0x2000000) ++ poke_fb(dev, fb, off - 4, off); ++ ++ amount = bios_rd32(bios, NV04_PFB_FIFO_DATA); ++ if (amount != peek_fb(dev, fb, amount - 4)) ++ /* IC missing - disable the upper half memory space. */ ++ bios_md32(bios, NV04_PFB_CFG0, mask, 0); ++ ++ io_mapping_free(fb); ++ return 0; ++} ++ + static int + init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + { +@@ -2047,64 +2394,57 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + * + * offset (8 bit): opcode + * +- * This opcode is meant to set NV_PFB_CFG0 (0x100200) appropriately so +- * that the hardware can correctly calculate how much VRAM it has +- * (and subsequently report that value in NV_PFB_CSTATUS (0x10020C)) ++ * This opcode is meant to set the PFB memory config registers ++ * appropriately so that we can correctly calculate how much VRAM it ++ * has (on nv10 and better chipsets the amount of installed VRAM is ++ * subsequently reported in NV_PFB_CSTATUS (0x10020C)). + * +- * The implementation of this opcode in general consists of two parts: +- * 1) determination of the memory bus width +- * 2) determination of how many of the card's RAM pads have ICs attached ++ * The implementation of this opcode in general consists of several ++ * parts: + * +- * 1) is done by a cunning combination of writes to offsets 0x1c and +- * 0x3c in the framebuffer, and seeing whether the written values are +- * read back correctly. This then affects bits 4-7 of NV_PFB_CFG0 ++ * 1) Determination of memory type and density. Only necessary for ++ * really old chipsets, the memory type reported by the strap bits ++ * (0x101000) is assumed to be accurate on nv05 and newer. + * +- * 2) is done by a cunning combination of writes to an offset slightly +- * less than the maximum memory reported by NV_PFB_CSTATUS, then seeing +- * if the test pattern can be read back. This then affects bits 12-15 of +- * NV_PFB_CFG0 ++ * 2) Determination of the memory bus width. Usually done by a cunning ++ * combination of writes to offsets 0x1c and 0x3c in the fb, and ++ * seeing whether the written values are read back correctly. + * +- * In this context a "cunning combination" may include multiple reads +- * and writes to varying locations, often alternating the test pattern +- * and 0, doubtless to make sure buffers are filled, residual charges +- * on tracks are removed etc. ++ * Only necessary on nv0x-nv1x and nv34, on the other cards we can ++ * trust the straps. + * +- * Unfortunately, the "cunning combination"s mentioned above, and the +- * changes to the bits in NV_PFB_CFG0 differ with nearly every bios +- * trace I have. ++ * 3) Determination of how many of the card's RAM pads have ICs ++ * attached, usually done by a cunning combination of writes to an ++ * offset slightly less than the maximum memory reported by ++ * NV_PFB_CSTATUS, then seeing if the test pattern can be read back. + * +- * Therefore, we cheat and assume the value of NV_PFB_CFG0 with which +- * we started was correct, and use that instead ++ * This appears to be a NOP on IGPs and NV4x or newer chipsets, both io ++ * logs of the VBIOS and kmmio traces of the binary driver POSTing the ++ * card show nothing being done for this opcode. Why is it still listed ++ * in the table?! + */ + + /* no iexec->execute check by design */ + +- /* +- * This appears to be a NOP on G8x chipsets, both io logs of the VBIOS +- * and kmmio traces of the binary driver POSTing the card show nothing +- * being done for this opcode. why is it still listed in the table?! +- */ +- + struct drm_nouveau_private *dev_priv = bios->dev->dev_private; ++ int ret; + +- if (dev_priv->card_type >= NV_40) +- return 1; +- +- /* +- * On every card I've seen, this step gets done for us earlier in +- * the init scripts +- uint8_t crdata = bios_idxprt_rd(dev, NV_VIO_SRX, 0x01); +- bios_idxprt_wr(dev, NV_VIO_SRX, 0x01, crdata | 0x20); +- */ +- +- /* +- * This also has probably been done in the scripts, but an mmio trace of +- * s3 resume shows nvidia doing it anyway (unlike the NV_VIO_SRX write) +- */ +- bios_wr32(bios, NV_PFB_REFCTRL, NV_PFB_REFCTRL_VALID_1); ++ if (dev_priv->chipset >= 0x40 || ++ dev_priv->chipset == 0x1a || ++ dev_priv->chipset == 0x1f) ++ ret = 0; ++ else if (dev_priv->chipset >= 0x20 && ++ dev_priv->chipset != 0x34) ++ ret = nv20_init_compute_mem(bios); ++ else if (dev_priv->chipset >= 0x10) ++ ret = nv10_init_compute_mem(bios); ++ else if (dev_priv->chipset >= 0x5) ++ ret = nv05_init_compute_mem(bios); ++ else ++ ret = nv04_init_compute_mem(bios); + +- /* write back the saved configuration value */ +- bios_wr32(bios, NV_PFB_CFG0, bios->state.saved_nv_pfb_cfg0); ++ if (ret) ++ return ret; + + return 1; + } +@@ -2131,7 +2471,8 @@ init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + /* no iexec->execute check by design */ + + pci_nv_19 = bios_rd32(bios, NV_PBUS_PCI_NV_19); +- bios_wr32(bios, NV_PBUS_PCI_NV_19, 0); ++ bios_wr32(bios, NV_PBUS_PCI_NV_19, pci_nv_19 & ~0xf00); ++ + bios_wr32(bios, reg, value1); + + udelay(10); +@@ -2167,7 +2508,7 @@ init_configure_mem(struct nvbios *bios, uint16_t offset, + uint32_t reg, data; + + if (bios->major_version > 2) +- return -ENODEV; ++ return 0; + + bios_idxprt_wr(bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX, bios_idxprt_rd( + bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX) | 0x20); +@@ -2180,14 +2521,14 @@ init_configure_mem(struct nvbios *bios, uint16_t offset, + reg = ROM32(bios->data[seqtbloffs += 4])) { + + switch (reg) { +- case NV_PFB_PRE: +- data = NV_PFB_PRE_CMD_PRECHARGE; ++ case NV04_PFB_PRE: ++ data = NV04_PFB_PRE_CMD_PRECHARGE; + break; +- case NV_PFB_PAD: +- data = NV_PFB_PAD_CKE_NORMAL; ++ case NV04_PFB_PAD: ++ data = NV04_PFB_PAD_CKE_NORMAL; + break; +- case NV_PFB_REF: +- data = NV_PFB_REF_CMD_REFRESH; ++ case NV04_PFB_REF: ++ data = NV04_PFB_REF_CMD_REFRESH; + break; + default: + data = ROM32(bios->data[meminitdata]); +@@ -2222,7 +2563,7 @@ init_configure_clk(struct nvbios *bios, uint16_t offset, + int clock; + + if (bios->major_version > 2) +- return -ENODEV; ++ return 0; + + clock = ROM16(bios->data[meminitoffs + 4]) * 10; + setPLL(bios, NV_PRAMDAC_NVPLL_COEFF, clock); +@@ -2255,7 +2596,7 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset, + uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6)); + + if (bios->major_version > 2) +- return -ENODEV; ++ return 0; + + bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, + NV_CIO_CRE_SCRATCH4__INDEX, cr3c); +@@ -2389,7 +2730,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset, + * offset + 1 (8 bit): mask + * offset + 2 (8 bit): cmpval + * +- * Test if (NV_PFB_BOOT_0 & "mask") equals "cmpval". ++ * Test if (NV04_PFB_BOOT_0 & "mask") equals "cmpval". + * If condition not met skip subsequent opcodes until condition is + * inverted (INIT_NOT), or we hit INIT_RESUME + */ +@@ -2401,7 +2742,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset, + if (!iexec->execute) + return 3; + +- data = bios_rd32(bios, NV_PFB_BOOT_0) & mask; ++ data = bios_rd32(bios, NV04_PFB_BOOT_0) & mask; + + BIOSLOG(bios, "0x%04X: Checking if 0x%08X equals 0x%08X\n", + offset, data, cmpval); +@@ -2800,7 +3141,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + + if (dev_priv->card_type != NV_50) { + NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n"); +- return -ENODEV; ++ return 1; + } + + if (!iexec->execute) +@@ -2872,10 +3213,7 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset, + uint8_t index; + int i; + +- +- if (!iexec->execute) +- return len; +- ++ /* critical! to know the length of the opcode */; + if (!blocklen) { + NV_ERROR(bios->dev, + "0x%04X: Zero block length - has the M table " +@@ -2883,6 +3221,9 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset, + return -EINVAL; + } + ++ if (!iexec->execute) ++ return len; ++ + strap_ramcfg = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 2) & 0xf; + index = bios->data[bios->ram_restrict_tbl_ptr + strap_ramcfg]; + +@@ -3064,14 +3405,14 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + + if (!bios->display.output) { + NV_ERROR(dev, "INIT_AUXCH: no active output\n"); +- return -EINVAL; ++ return len; + } + + auxch = init_i2c_device_find(dev, bios->display.output->i2c_index); + if (!auxch) { + NV_ERROR(dev, "INIT_AUXCH: couldn't get auxch %d\n", + bios->display.output->i2c_index); +- return -ENODEV; ++ return len; + } + + if (!iexec->execute) +@@ -3084,7 +3425,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + ret = nouveau_dp_auxch(auxch, 9, addr, &data, 1); + if (ret) { + NV_ERROR(dev, "INIT_AUXCH: rd auxch fail %d\n", ret); +- return ret; ++ return len; + } + + data &= bios->data[offset + 0]; +@@ -3093,7 +3434,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + ret = nouveau_dp_auxch(auxch, 8, addr, &data, 1); + if (ret) { + NV_ERROR(dev, "INIT_AUXCH: wr auxch fail %d\n", ret); +- return ret; ++ return len; + } + } + +@@ -3123,14 +3464,14 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + + if (!bios->display.output) { + NV_ERROR(dev, "INIT_ZM_AUXCH: no active output\n"); +- return -EINVAL; ++ return len; + } + + auxch = init_i2c_device_find(dev, bios->display.output->i2c_index); + if (!auxch) { + NV_ERROR(dev, "INIT_ZM_AUXCH: couldn't get auxch %d\n", + bios->display.output->i2c_index); +- return -ENODEV; ++ return len; + } + + if (!iexec->execute) +@@ -3141,7 +3482,7 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1); + if (ret) { + NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret); +- return ret; ++ return len; + } + } + +@@ -5151,10 +5492,14 @@ 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]; +- bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4]; +- bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5]; +- bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6]; +- bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7]; ++ if (bios->data[legacy_i2c_offset + 4]) ++ bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4]; ++ if (bios->data[legacy_i2c_offset + 5]) ++ bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5]; ++ if (bios->data[legacy_i2c_offset + 6]) ++ bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6]; ++ if (bios->data[legacy_i2c_offset + 7]) ++ bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7]; + + if (bmplength > 74) { + bios->fmaxvco = ROM32(bmp[67]); +@@ -5589,9 +5934,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, + if (conf & 0x4 || conf & 0x8) + entry->lvdsconf.use_power_scripts = true; + } else { +- mask = ~0x5; ++ mask = ~0x7; ++ if (conf & 0x2) ++ entry->lvdsconf.use_acpi_for_edid = true; + if (conf & 0x4) + entry->lvdsconf.use_power_scripts = true; ++ entry->lvdsconf.sor.link = (conf & 0x00000030) >> 4; + } + if (conf & mask) { + /* +@@ -5706,13 +6054,6 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, + case OUTPUT_TV: + entry->tvconf.has_component_output = false; + break; +- case OUTPUT_TMDS: +- /* +- * Invent a DVI-A output, by copying the fields of the DVI-D +- * output; reported to work by math_b on an NV20(!). +- */ +- fabricate_vga_output(dcb, entry->i2c_index, entry->heads); +- break; + case OUTPUT_LVDS: + if ((conn & 0x00003f00) != 0x10) + entry->lvdsconf.use_straps_for_mode = true; +@@ -5793,6 +6134,31 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) + dcb->entries = newentries; + } + ++static bool ++apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) ++{ ++ /* Dell Precision M6300 ++ * DCB entry 2: 02025312 00000010 ++ * DCB entry 3: 02026312 00000020 ++ * ++ * Identical, except apparently a different connector on a ++ * different SOR link. Not a clue how we're supposed to know ++ * which one is in use if it even shares an i2c line... ++ * ++ * Ignore the connector on the second SOR link to prevent ++ * nasty problems until this is sorted (assuming it's not a ++ * VBIOS bug). ++ */ ++ if ((dev->pdev->device == 0x040d) && ++ (dev->pdev->subsystem_vendor == 0x1028) && ++ (dev->pdev->subsystem_device == 0x019b)) { ++ if (*conn == 0x02026312 && *conf == 0x00000020) ++ return false; ++ } ++ ++ return true; ++} ++ + static int + parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) + { +@@ -5926,6 +6292,9 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) + if ((connection & 0x0000000f) == 0x0000000f) + continue; + ++ if (!apply_dcb_encoder_quirks(dev, i, &connection, &config)) ++ continue; ++ + NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n", + dcb->entries, connection, config); + +@@ -6182,8 +6551,10 @@ nouveau_run_vbios_init(struct drm_device *dev) + int i, ret = 0; + + NVLockVgaCrtcs(dev, false); +- if (nv_two_heads(dev)) +- NVSetOwner(dev, bios->state.crtchead); ++ if (nv_two_heads(dev)) { ++ bios->state.crtchead = 0; ++ NVSetOwner(dev, 0); ++ } + + if (bios->major_version < 5) /* BMP only */ + load_nv17_hw_sequencer_ucode(dev, bios); +@@ -6238,7 +6609,6 @@ static bool + nouveau_bios_posted(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- bool was_locked; + unsigned htotal; + + if (dev_priv->chipset >= NV_50) { +@@ -6248,13 +6618,14 @@ nouveau_bios_posted(struct drm_device *dev) + return true; + } + +- was_locked = NVLockVgaCrtcs(dev, false); ++ NVLockVgaCrtcs(dev, false); + htotal = NVReadVgaCrtc(dev, 0, 0x06); + htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8; + htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4; + htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10; + htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11; +- NVLockVgaCrtcs(dev, was_locked); ++ NVLockVgaCrtcs(dev, true); ++ + return (htotal != 0); + } + +@@ -6263,8 +6634,6 @@ nouveau_bios_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; +- uint32_t saved_nv_pextdev_boot_0; +- bool was_locked; + int ret; + + if (!NVInitVBIOS(dev)) +@@ -6284,40 +6653,29 @@ nouveau_bios_init(struct drm_device *dev) + if (!bios->major_version) /* we don't run version 0 bios */ + return 0; + +- /* these will need remembering across a suspend */ +- saved_nv_pextdev_boot_0 = bios_rd32(bios, NV_PEXTDEV_BOOT_0); +- bios->state.saved_nv_pfb_cfg0 = bios_rd32(bios, NV_PFB_CFG0); +- + /* init script execution disabled */ + bios->execute = false; + + /* ... unless card isn't POSTed already */ + if (!nouveau_bios_posted(dev)) { +- NV_INFO(dev, "Adaptor not initialised\n"); +- if (dev_priv->card_type < NV_40) { +- NV_ERROR(dev, "Unable to POST this chipset\n"); +- return -ENODEV; +- } +- +- NV_INFO(dev, "Running VBIOS init tables\n"); ++ NV_INFO(dev, "Adaptor not initialised, " ++ "running VBIOS init tables.\n"); + bios->execute = true; + } + +- bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0); +- + ret = nouveau_run_vbios_init(dev); + if (ret) + return ret; + + /* feature_byte on BMP is poor, but init always sets CR4B */ +- was_locked = NVLockVgaCrtcs(dev, false); ++ NVLockVgaCrtcs(dev, false); + if (bios->major_version < 5) + bios->is_mobile = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_4B) & 0x40; + + /* all BIT systems need p_f_m_t for digital_min_front_porch */ + if (bios->is_mobile || bios->major_version >= 5) + ret = parse_fp_mode_table(dev, bios); +- NVLockVgaCrtcs(dev, was_locked); ++ NVLockVgaCrtcs(dev, true); + + /* allow subsequent scripts to execute */ + bios->execute = true; +diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h +index adf4ec2..024458a 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bios.h ++++ b/drivers/gpu/drm/nouveau/nouveau_bios.h +@@ -81,6 +81,7 @@ struct dcb_connector_table_entry { + enum dcb_connector_type type; + uint8_t index2; + uint8_t gpio_tag; ++ void *drm; + }; + + struct dcb_connector_table { +@@ -117,6 +118,7 @@ struct dcb_entry { + struct { + struct sor_conf sor; + bool use_straps_for_mode; ++ bool use_acpi_for_edid; + bool use_power_scripts; + } lvdsconf; + struct { +@@ -249,8 +251,6 @@ struct nvbios { + + struct { + int crtchead; +- /* these need remembering across suspend */ +- uint32_t saved_nv_pfb_cfg0; + } state; + + struct { +diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c +index 6f3c195..d8c341d 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bo.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c +@@ -461,9 +461,9 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, + return ret; + + ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, +- evict, no_wait_reserve, no_wait_gpu, new_mem); +- if (nvbo->channel && nvbo->channel != chan) +- ret = nouveau_fence_wait(fence, NULL, false, false); ++ evict || (nvbo->channel && ++ nvbo->channel != chan), ++ no_wait_reserve, no_wait_gpu, new_mem); + nouveau_fence_unref((void *)&fence); + return ret; + } +@@ -711,8 +711,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, + return ret; + + /* Software copy if the card isn't up and running yet. */ +- if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE || +- !dev_priv->channel) { ++ if (!dev_priv->channel) { + ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); + goto out; + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c +index 88f9bc0..ca85da7 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_calc.c ++++ b/drivers/gpu/drm/nouveau/nouveau_calc.c +@@ -200,7 +200,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, + struct nv_sim_state sim_data; + int MClk = nouveau_hw_get_clock(dev, MPLL); + int NVClk = nouveau_hw_get_clock(dev, NVPLL); +- uint32_t cfg1 = nvReadFB(dev, NV_PFB_CFG1); ++ uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1); + + sim_data.pclk_khz = VClk; + sim_data.mclk_khz = MClk; +@@ -218,7 +218,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, + sim_data.mem_latency = 3; + sim_data.mem_page_miss = 10; + } else { +- sim_data.memory_type = nvReadFB(dev, NV_PFB_CFG0) & 0x1; ++ sim_data.memory_type = nvReadFB(dev, NV04_PFB_CFG0) & 0x1; + sim_data.memory_width = (nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64; + sim_data.mem_latency = cfg1 & 0xf; + sim_data.mem_page_miss = ((cfg1 >> 4) & 0xf) + ((cfg1 >> 31) & 0x1); +diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c +index 1fc57ef..e952c3b 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_channel.c ++++ b/drivers/gpu/drm/nouveau/nouveau_channel.c +@@ -257,9 +257,7 @@ nouveau_channel_free(struct nouveau_channel *chan) + nouveau_debugfs_channel_fini(chan); + + /* Give outstanding push buffers a chance to complete */ +- spin_lock_irqsave(&chan->fence.lock, flags); + nouveau_fence_update(chan); +- spin_unlock_irqrestore(&chan->fence.lock, flags); + if (chan->fence.sequence != chan->fence.sequence_ack) { + struct nouveau_fence *fence = NULL; + +@@ -368,8 +366,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, + struct nouveau_channel *chan; + int ret; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; +- + if (dev_priv->engine.graph.accel_blocked) + return -ENODEV; + +@@ -418,7 +414,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, + struct drm_nouveau_channel_free *cfree = data; + struct nouveau_channel *chan; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan); + + nouveau_channel_free(chan); +diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c +index 149ed22..734e926 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_connector.c ++++ b/drivers/gpu/drm/nouveau/nouveau_connector.c +@@ -102,63 +102,15 @@ nouveau_connector_destroy(struct drm_connector *drm_connector) + kfree(drm_connector); + } + +-static void +-nouveau_connector_ddc_prepare(struct drm_connector *connector, int *flags) +-{ +- struct drm_nouveau_private *dev_priv = connector->dev->dev_private; +- +- if (dev_priv->card_type >= NV_50) +- return; +- +- *flags = 0; +- if (NVLockVgaCrtcs(dev_priv->dev, false)) +- *flags |= 1; +- if (nv_heads_tied(dev_priv->dev)) +- *flags |= 2; +- +- if (*flags & 2) +- NVSetOwner(dev_priv->dev, 0); /* necessary? */ +-} +- +-static void +-nouveau_connector_ddc_finish(struct drm_connector *connector, int flags) +-{ +- struct drm_nouveau_private *dev_priv = connector->dev->dev_private; +- +- if (dev_priv->card_type >= NV_50) +- return; +- +- if (flags & 2) +- NVSetOwner(dev_priv->dev, 4); +- if (flags & 1) +- NVLockVgaCrtcs(dev_priv->dev, true); +-} +- + static struct nouveau_i2c_chan * + nouveau_connector_ddc_detect(struct drm_connector *connector, + struct nouveau_encoder **pnv_encoder) + { + struct drm_device *dev = connector->dev; +- uint8_t out_buf[] = { 0x0, 0x0}, buf[2]; +- int ret, flags, i; +- +- struct i2c_msg msgs[] = { +- { +- .addr = 0x50, +- .flags = 0, +- .len = 1, +- .buf = out_buf, +- }, +- { +- .addr = 0x50, +- .flags = I2C_M_RD, +- .len = 1, +- .buf = buf, +- } +- }; ++ int i; + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { +- struct nouveau_i2c_chan *i2c = NULL; ++ struct nouveau_i2c_chan *i2c; + struct nouveau_encoder *nv_encoder; + struct drm_mode_object *obj; + int id; +@@ -171,17 +123,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, + if (!obj) + continue; + nv_encoder = nouveau_encoder(obj_to_encoder(obj)); ++ i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); + +- if (nv_encoder->dcb->i2c_index < 0xf) +- i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); +- if (!i2c) +- continue; +- +- nouveau_connector_ddc_prepare(connector, &flags); +- ret = i2c_transfer(&i2c->adapter, msgs, 2); +- nouveau_connector_ddc_finish(connector, flags); +- +- if (ret == 2) { ++ if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) { + *pnv_encoder = nv_encoder; + return i2c; + } +@@ -234,21 +178,7 @@ nouveau_connector_detect(struct drm_connector *connector) + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct nouveau_encoder *nv_encoder = NULL; + struct nouveau_i2c_chan *i2c; +- int type, flags; +- +- if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS) +- nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); +- if (nv_encoder && nv_connector->native_mode) { +- unsigned status = connector_status_connected; +- +-#if defined(CONFIG_ACPI_BUTTON) || \ +- (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE)) +- if (!nouveau_ignorelid && !acpi_lid_open()) +- status = connector_status_unknown; +-#endif +- nouveau_connector_set_encoder(connector, nv_encoder); +- return status; +- } ++ int type; + + /* Cleanup the previous EDID block. */ + if (nv_connector->edid) { +@@ -259,9 +189,7 @@ nouveau_connector_detect(struct drm_connector *connector) + + i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); + if (i2c) { +- nouveau_connector_ddc_prepare(connector, &flags); + nv_connector->edid = drm_get_edid(connector, &i2c->adapter); +- nouveau_connector_ddc_finish(connector, flags); + drm_mode_connector_update_edid_property(connector, + nv_connector->edid); + if (!nv_connector->edid) { +@@ -321,6 +249,85 @@ detect_analog: + return connector_status_disconnected; + } + ++static enum drm_connector_status ++nouveau_connector_detect_lvds(struct drm_connector *connector) ++{ ++ struct drm_device *dev = connector->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_connector *nv_connector = nouveau_connector(connector); ++ struct nouveau_encoder *nv_encoder = NULL; ++ enum drm_connector_status status = connector_status_disconnected; ++ ++ /* Cleanup the previous EDID block. */ ++ if (nv_connector->edid) { ++ drm_mode_connector_update_edid_property(connector, NULL); ++ kfree(nv_connector->edid); ++ nv_connector->edid = NULL; ++ } ++ ++ nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); ++ if (!nv_encoder) ++ return connector_status_disconnected; ++ ++ /* Try retrieving EDID via DDC */ ++ if (!dev_priv->vbios.fp_no_ddc) { ++ status = nouveau_connector_detect(connector); ++ if (status == connector_status_connected) ++ goto out; ++ } ++ ++ /* On some laptops (Sony, i'm looking at you) there appears to ++ * be no direct way of accessing the panel's EDID. The only ++ * option available to us appears to be to ask ACPI for help.. ++ * ++ * It's important this check's before trying straps, one of the ++ * said manufacturer's laptops are configured in such a way ++ * the nouveau decides an entry in the VBIOS FP mode table is ++ * valid - it's not (rh#613284) ++ */ ++ if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) { ++ if (!nouveau_acpi_edid(dev, connector)) { ++ status = connector_status_connected; ++ goto out; ++ } ++ } ++ ++ /* If no EDID found above, and the VBIOS indicates a hardcoded ++ * modeline is avalilable for the panel, set it as the panel's ++ * native mode and exit. ++ */ ++ if (nouveau_bios_fp_mode(dev, NULL) && (dev_priv->vbios.fp_no_ddc || ++ nv_encoder->dcb->lvdsconf.use_straps_for_mode)) { ++ status = connector_status_connected; ++ goto out; ++ } ++ ++ /* Still nothing, some VBIOS images have a hardcoded EDID block ++ * stored for the panel stored in them. ++ */ ++ if (!dev_priv->vbios.fp_no_ddc) { ++ struct edid *edid = ++ (struct edid *)nouveau_bios_embedded_edid(dev); ++ if (edid) { ++ nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL); ++ *(nv_connector->edid) = *edid; ++ status = connector_status_connected; ++ } ++ } ++ ++out: ++#if defined(CONFIG_ACPI_BUTTON) || \ ++ (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE)) ++ if (status == connector_status_connected && ++ !nouveau_ignorelid && !acpi_lid_open()) ++ status = connector_status_unknown; ++#endif ++ ++ drm_mode_connector_update_edid_property(connector, nv_connector->edid); ++ nouveau_connector_set_encoder(connector, nv_encoder); ++ return status; ++} ++ + static void + nouveau_connector_force(struct drm_connector *connector) + { +@@ -441,7 +448,8 @@ nouveau_connector_native_mode(struct drm_connector *connector) + int high_w = 0, high_h = 0, high_v = 0; + + list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { +- if (helper->mode_valid(connector, mode) != MODE_OK) ++ if (helper->mode_valid(connector, mode) != MODE_OK || ++ (mode->flags & DRM_MODE_FLAG_INTERLACE)) + continue; + + /* Use preferred mode if there is one.. */ +@@ -534,21 +542,27 @@ static int + nouveau_connector_get_modes(struct drm_connector *connector) + { + struct drm_device *dev = connector->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; + int ret = 0; + +- /* If we're not LVDS, destroy the previous native mode, the attached +- * monitor could have changed. ++ /* destroy the native mode, the attached monitor could have changed. + */ +- if (nv_connector->dcb->type != DCB_CONNECTOR_LVDS && +- nv_connector->native_mode) { ++ if (nv_connector->native_mode) { + drm_mode_destroy(dev, nv_connector->native_mode); + nv_connector->native_mode = NULL; + } + + if (nv_connector->edid) + ret = drm_add_edid_modes(connector, nv_connector->edid); ++ else ++ if (nv_encoder->dcb->type == OUTPUT_LVDS && ++ (nv_encoder->dcb->lvdsconf.use_straps_for_mode || ++ dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) { ++ nv_connector->native_mode = drm_mode_create(dev); ++ nouveau_bios_fp_mode(dev, nv_connector->native_mode); ++ } + + /* Find the native mode if this is a digital panel, if we didn't + * find any modes through DDC previously add the native mode to +@@ -569,7 +583,8 @@ nouveau_connector_get_modes(struct drm_connector *connector) + ret = get_slave_funcs(nv_encoder)-> + get_modes(to_drm_encoder(nv_encoder), connector); + +- if (nv_encoder->dcb->type == OUTPUT_LVDS) ++ if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS || ++ nv_connector->dcb->type == DCB_CONNECTOR_eDP) + ret += nouveau_connector_scaler_modes_add(connector); + + return ret; +@@ -643,6 +658,44 @@ nouveau_connector_best_encoder(struct drm_connector *connector) + return NULL; + } + ++void ++nouveau_connector_set_polling(struct drm_connector *connector) ++{ ++ struct drm_device *dev = connector->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct drm_crtc *crtc; ++ bool spare_crtc = false; ++ ++ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) ++ spare_crtc |= !crtc->enabled; ++ ++ connector->polled = 0; ++ ++ switch (connector->connector_type) { ++ case DRM_MODE_CONNECTOR_VGA: ++ case DRM_MODE_CONNECTOR_TV: ++ if (dev_priv->card_type >= NV_50 || ++ (nv_gf4_disp_arch(dev) && spare_crtc)) ++ connector->polled = DRM_CONNECTOR_POLL_CONNECT; ++ break; ++ ++ case DRM_MODE_CONNECTOR_DVII: ++ case DRM_MODE_CONNECTOR_DVID: ++ case DRM_MODE_CONNECTOR_HDMIA: ++ case DRM_MODE_CONNECTOR_DisplayPort: ++ case DRM_MODE_CONNECTOR_eDP: ++ if (dev_priv->card_type >= NV_50) ++ connector->polled = DRM_CONNECTOR_POLL_HPD; ++ else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID || ++ spare_crtc) ++ connector->polled = DRM_CONNECTOR_POLL_CONNECT; ++ break; ++ ++ default: ++ break; ++ } ++} ++ + static const struct drm_connector_helper_funcs + nouveau_connector_helper_funcs = { + .get_modes = nouveau_connector_get_modes, +@@ -662,148 +715,74 @@ nouveau_connector_funcs = { + .force = nouveau_connector_force + }; + +-static int +-nouveau_connector_create_lvds(struct drm_device *dev, +- struct drm_connector *connector) +-{ +- struct nouveau_connector *nv_connector = nouveau_connector(connector); +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_i2c_chan *i2c = NULL; +- struct nouveau_encoder *nv_encoder; +- struct drm_display_mode native, *mode, *temp; +- bool dummy, if_is_24bit = false; +- int ret, flags; +- +- nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); +- if (!nv_encoder) +- return -ENODEV; +- +- ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &if_is_24bit); +- if (ret) { +- NV_ERROR(dev, "Error parsing LVDS table, disabling LVDS\n"); +- return ret; +- } +- nv_connector->use_dithering = !if_is_24bit; +- +- /* Firstly try getting EDID over DDC, if allowed and I2C channel +- * is available. +- */ +- if (!dev_priv->vbios.fp_no_ddc && nv_encoder->dcb->i2c_index < 0xf) +- i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); +- +- if (i2c) { +- nouveau_connector_ddc_prepare(connector, &flags); +- nv_connector->edid = drm_get_edid(connector, &i2c->adapter); +- nouveau_connector_ddc_finish(connector, flags); +- } +- +- /* If no EDID found above, and the VBIOS indicates a hardcoded +- * modeline is avalilable for the panel, set it as the panel's +- * native mode and exit. +- */ +- if (!nv_connector->edid && nouveau_bios_fp_mode(dev, &native) && +- (nv_encoder->dcb->lvdsconf.use_straps_for_mode || +- dev_priv->vbios.fp_no_ddc)) { +- nv_connector->native_mode = drm_mode_duplicate(dev, &native); +- goto out; +- } +- +- /* Still nothing, some VBIOS images have a hardcoded EDID block +- * stored for the panel stored in them. +- */ +- if (!nv_connector->edid && !nv_connector->native_mode && +- !dev_priv->vbios.fp_no_ddc) { +- struct edid *edid = +- (struct edid *)nouveau_bios_embedded_edid(dev); +- if (edid) { +- nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL); +- *(nv_connector->edid) = *edid; +- } +- } +- +- if (!nv_connector->edid) +- goto out; +- +- /* We didn't find/use a panel mode from the VBIOS, so parse the EDID +- * block and look for the preferred mode there. +- */ +- ret = drm_add_edid_modes(connector, nv_connector->edid); +- if (ret == 0) +- goto out; +- nv_connector->detected_encoder = nv_encoder; +- nv_connector->native_mode = nouveau_connector_native_mode(connector); +- list_for_each_entry_safe(mode, temp, &connector->probed_modes, head) +- drm_mode_remove(connector, mode); +- +-out: +- if (!nv_connector->native_mode) { +- NV_ERROR(dev, "LVDS present in DCB table, but couldn't " +- "determine its native mode. Disabling.\n"); +- return -ENODEV; +- } +- +- drm_mode_connector_update_edid_property(connector, nv_connector->edid); +- return 0; +-} ++static const struct drm_connector_funcs ++nouveau_connector_funcs_lvds = { ++ .dpms = drm_helper_connector_dpms, ++ .save = NULL, ++ .restore = NULL, ++ .detect = nouveau_connector_detect_lvds, ++ .destroy = nouveau_connector_destroy, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .set_property = nouveau_connector_set_property, ++ .force = nouveau_connector_force ++}; + +-int +-nouveau_connector_create(struct drm_device *dev, +- struct dcb_connector_table_entry *dcb) ++struct drm_connector * ++nouveau_connector_create(struct drm_device *dev, int index) + { ++ const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_connector *nv_connector = NULL; ++ struct dcb_connector_table_entry *dcb = NULL; + struct drm_connector *connector; +- struct drm_encoder *encoder; +- int ret, type; ++ int type, ret = 0; + + NV_DEBUG_KMS(dev, "\n"); + ++ if (index >= dev_priv->vbios.dcb.connector.entries) ++ return ERR_PTR(-EINVAL); ++ ++ dcb = &dev_priv->vbios.dcb.connector.entry[index]; ++ if (dcb->drm) ++ return dcb->drm; ++ + switch (dcb->type) { +- case DCB_CONNECTOR_NONE: +- return 0; + case DCB_CONNECTOR_VGA: +- NV_INFO(dev, "Detected a VGA connector\n"); + type = DRM_MODE_CONNECTOR_VGA; + break; + case DCB_CONNECTOR_TV_0: + case DCB_CONNECTOR_TV_1: + case DCB_CONNECTOR_TV_3: +- NV_INFO(dev, "Detected a TV connector\n"); + type = DRM_MODE_CONNECTOR_TV; + break; + case DCB_CONNECTOR_DVI_I: +- NV_INFO(dev, "Detected a DVI-I connector\n"); + type = DRM_MODE_CONNECTOR_DVII; + break; + case DCB_CONNECTOR_DVI_D: +- NV_INFO(dev, "Detected a DVI-D connector\n"); + type = DRM_MODE_CONNECTOR_DVID; + break; + case DCB_CONNECTOR_HDMI_0: + case DCB_CONNECTOR_HDMI_1: +- NV_INFO(dev, "Detected a HDMI connector\n"); + type = DRM_MODE_CONNECTOR_HDMIA; + break; + case DCB_CONNECTOR_LVDS: +- NV_INFO(dev, "Detected a LVDS connector\n"); + type = DRM_MODE_CONNECTOR_LVDS; ++ funcs = &nouveau_connector_funcs_lvds; + break; + case DCB_CONNECTOR_DP: +- NV_INFO(dev, "Detected a DisplayPort connector\n"); + type = DRM_MODE_CONNECTOR_DisplayPort; + break; + case DCB_CONNECTOR_eDP: +- NV_INFO(dev, "Detected an eDP connector\n"); + type = DRM_MODE_CONNECTOR_eDP; + break; + default: + NV_ERROR(dev, "unknown connector type: 0x%02x!!\n", dcb->type); +- return -EINVAL; ++ return ERR_PTR(-EINVAL); + } + + nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); + if (!nv_connector) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + nv_connector->dcb = dcb; + connector = &nv_connector->base; + +@@ -811,27 +790,21 @@ nouveau_connector_create(struct drm_device *dev, + connector->interlace_allowed = false; + connector->doublescan_allowed = false; + +- drm_connector_init(dev, connector, &nouveau_connector_funcs, type); ++ drm_connector_init(dev, connector, funcs, type); + drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); + +- /* attach encoders */ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- +- if (nv_encoder->dcb->connector != dcb->index) +- continue; +- +- if (get_slave_funcs(nv_encoder)) +- get_slave_funcs(nv_encoder)->create_resources(encoder, connector); ++ /* Check if we need dithering enabled */ ++ if (dcb->type == DCB_CONNECTOR_LVDS) { ++ bool dummy, is_24bit = false; + +- drm_mode_connector_attach_encoder(connector, encoder); +- } ++ ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit); ++ if (ret) { ++ NV_ERROR(dev, "Error parsing LVDS table, disabling " ++ "LVDS\n"); ++ goto fail; ++ } + +- if (!connector->encoder_ids[0]) { +- NV_WARN(dev, " no encoders, ignoring\n"); +- drm_connector_cleanup(connector); +- kfree(connector); +- return 0; ++ nv_connector->use_dithering = !is_24bit; + } + + /* Init DVI-I specific properties */ +@@ -841,12 +814,8 @@ nouveau_connector_create(struct drm_device *dev, + drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0); + } + +- if (dcb->type != DCB_CONNECTOR_LVDS) +- nv_connector->use_dithering = false; +- + switch (dcb->type) { + case DCB_CONNECTOR_VGA: +- connector->polled = DRM_CONNECTOR_POLL_CONNECT; + if (dev_priv->card_type >= NV_50) { + drm_connector_attach_property(connector, + dev->mode_config.scaling_mode_property, +@@ -858,17 +827,6 @@ nouveau_connector_create(struct drm_device *dev, + case DCB_CONNECTOR_TV_3: + nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; + break; +- case DCB_CONNECTOR_DP: +- case DCB_CONNECTOR_eDP: +- case DCB_CONNECTOR_HDMI_0: +- case DCB_CONNECTOR_HDMI_1: +- case DCB_CONNECTOR_DVI_I: +- case DCB_CONNECTOR_DVI_D: +- if (dev_priv->card_type >= NV_50) +- connector->polled = DRM_CONNECTOR_POLL_HPD; +- else +- connector->polled = DRM_CONNECTOR_POLL_CONNECT; +- /* fall-through */ + default: + nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; + +@@ -882,15 +840,15 @@ nouveau_connector_create(struct drm_device *dev, + break; + } + ++ nouveau_connector_set_polling(connector); ++ + drm_sysfs_connector_add(connector); ++ dcb->drm = connector; ++ return dcb->drm; + +- if (dcb->type == DCB_CONNECTOR_LVDS) { +- ret = nouveau_connector_create_lvds(dev, connector); +- if (ret) { +- connector->funcs->destroy(connector); +- return ret; +- } +- } ++fail: ++ drm_connector_cleanup(connector); ++ kfree(connector); ++ return ERR_PTR(ret); + +- return 0; + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h +index 4ef38ab..0d2e668 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_connector.h ++++ b/drivers/gpu/drm/nouveau/nouveau_connector.h +@@ -49,7 +49,10 @@ static inline struct nouveau_connector *nouveau_connector( + return container_of(con, struct nouveau_connector, base); + } + +-int nouveau_connector_create(struct drm_device *, +- struct dcb_connector_table_entry *); ++struct drm_connector * ++nouveau_connector_create(struct drm_device *, int index); ++ ++void ++nouveau_connector_set_polling(struct drm_connector *); + + #endif /* __NOUVEAU_CONNECTOR_H__ */ +diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c +index 65c441a..2e3c6ca 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_dma.c ++++ b/drivers/gpu/drm/nouveau/nouveau_dma.c +@@ -92,11 +92,9 @@ nouveau_dma_init(struct nouveau_channel *chan) + return ret; + + /* Map M2MF notifier object - fbcon. */ +- if (drm_core_check_feature(dev, DRIVER_MODESET)) { +- ret = nouveau_bo_map(chan->notifier_bo); +- if (ret) +- return ret; +- } ++ ret = nouveau_bo_map(chan->notifier_bo); ++ if (ret) ++ return ret; + + /* Insert NOPS for NOUVEAU_DMA_SKIPS */ + ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); +diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c +index deeb21c..184bc95 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_dp.c ++++ b/drivers/gpu/drm/nouveau/nouveau_dp.c +@@ -271,12 +271,26 @@ nouveau_dp_link_train(struct drm_encoder *encoder) + { + struct drm_device *dev = encoder->dev; + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- uint8_t config[4]; +- uint8_t status[3]; ++ struct bit_displayport_encoder_table *dpe; ++ int dpe_headerlen; ++ uint8_t config[4], status[3]; + bool cr_done, cr_max_vs, eq_done; + int ret = 0, i, tries, voltage; + + NV_DEBUG_KMS(dev, "link training!!\n"); ++ ++ dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); ++ if (!dpe) { ++ NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or); ++ return false; ++ } ++ ++ if (dpe->script0) { ++ NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); ++ nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0), ++ nv_encoder->dcb); ++ } ++ + train: + cr_done = eq_done = false; + +@@ -403,6 +417,12 @@ stop: + } + } + ++ if (dpe->script1) { ++ NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or); ++ nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1), ++ nv_encoder->dcb); ++ } ++ + return eq_done; + } + +diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c +index 2737704..203d0b6 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drv.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.c +@@ -35,10 +35,6 @@ + + #include "drm_pciids.h" + +-MODULE_PARM_DESC(ctxfw, "Use external firmware blob for grctx init (NV40)"); +-int nouveau_ctxfw = 0; +-module_param_named(ctxfw, nouveau_ctxfw, int, 0400); +- + MODULE_PARM_DESC(noagp, "Disable AGP"); + int nouveau_noagp; + module_param_named(noagp, nouveau_noagp, int, 0400); +@@ -56,7 +52,7 @@ int nouveau_vram_pushbuf; + module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); + + MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM"); +-int nouveau_vram_notify = 1; ++int nouveau_vram_notify = 0; + module_param_named(vram_notify, nouveau_vram_notify, int, 0400); + + MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)"); +@@ -155,9 +151,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) + struct drm_crtc *crtc; + int ret, i; + +- if (!drm_core_check_feature(dev, DRIVER_MODESET)) +- return -ENODEV; +- + if (pm_state.event == PM_EVENT_PRETHAW) + return 0; + +@@ -257,9 +250,6 @@ nouveau_pci_resume(struct pci_dev *pdev) + struct drm_crtc *crtc; + int ret, i; + +- if (!drm_core_check_feature(dev, DRIVER_MODESET)) +- return -ENODEV; +- + nouveau_fbcon_save_disable_accel(dev); + + NV_INFO(dev, "We're back, enabling device...\n"); +@@ -323,7 +313,6 @@ nouveau_pci_resume(struct pci_dev *pdev) + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); +- int ret; + + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); + if (!ret) +@@ -332,10 +321,9 @@ nouveau_pci_resume(struct pci_dev *pdev) + NV_ERROR(dev, "Could not pin/map cursor.\n"); + } + +- if (dev_priv->card_type < NV_50) { ++ if (dev_priv->card_type < NV_50) + nv04_display_restore(dev); +- NVLockVgaCrtcs(dev, false); +- } else ++ else + nv50_display_init(dev); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { +@@ -371,7 +359,8 @@ nouveau_pci_resume(struct pci_dev *pdev) + static struct drm_driver driver = { + .driver_features = + DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | +- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM, ++ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | ++ DRIVER_MODESET, + .load = nouveau_load, + .firstopen = nouveau_firstopen, + .lastclose = nouveau_lastclose, +@@ -438,16 +427,18 @@ static int __init nouveau_init(void) + nouveau_modeset = 1; + } + +- if (nouveau_modeset == 1) { +- driver.driver_features |= DRIVER_MODESET; +- nouveau_register_dsm_handler(); +- } ++ if (!nouveau_modeset) ++ return 0; + ++ nouveau_register_dsm_handler(); + return drm_init(&driver); + } + + static void __exit nouveau_exit(void) + { ++ if (!nouveau_modeset) ++ return; ++ + drm_exit(&driver); + nouveau_unregister_dsm_handler(); + } +diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h +index c697191..20ca5b8 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drv.h ++++ b/drivers/gpu/drm/nouveau/nouveau_drv.h +@@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo) + return ioptr; + } + +-struct mem_block { +- struct mem_block *next; +- struct mem_block *prev; +- uint64_t start; +- uint64_t size; +- struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */ +-}; +- + enum nouveau_flags { + NV_NFORCE = 0x10000000, + NV_NFORCE2 = 0x20000000 +@@ -149,7 +141,7 @@ struct nouveau_gpuobj { + struct list_head list; + + struct nouveau_channel *im_channel; +- struct mem_block *im_pramin; ++ struct drm_mm_node *im_pramin; + struct nouveau_bo *im_backing; + uint32_t im_backing_start; + uint32_t *im_backing_suspend; +@@ -196,7 +188,7 @@ struct nouveau_channel { + struct list_head pending; + uint32_t sequence; + uint32_t sequence_ack; +- uint32_t last_sequence_irq; ++ atomic_t last_sequence_irq; + } fence; + + /* DMA push buffer */ +@@ -206,7 +198,7 @@ struct nouveau_channel { + + /* Notifier memory */ + struct nouveau_bo *notifier_bo; +- struct mem_block *notifier_heap; ++ struct drm_mm notifier_heap; + + /* PFIFO context */ + struct nouveau_gpuobj_ref *ramfc; +@@ -224,7 +216,7 @@ struct nouveau_channel { + + /* Objects */ + struct nouveau_gpuobj_ref *ramin; /* Private instmem */ +- struct mem_block *ramin_heap; /* Private PRAMIN heap */ ++ struct drm_mm ramin_heap; /* Private PRAMIN heap */ + struct nouveau_gpuobj_ref *ramht; /* Hash table */ + struct list_head ramht_refs; /* Objects referenced by RAMHT */ + +@@ -277,8 +269,7 @@ struct nouveau_instmem_engine { + void (*clear)(struct drm_device *, struct nouveau_gpuobj *); + int (*bind)(struct drm_device *, struct nouveau_gpuobj *); + int (*unbind)(struct drm_device *, struct nouveau_gpuobj *); +- void (*prepare_access)(struct drm_device *, bool write); +- void (*finish_access)(struct drm_device *); ++ void (*flush)(struct drm_device *); + }; + + struct nouveau_mc_engine { +@@ -303,10 +294,11 @@ struct nouveau_fb_engine { + }; + + struct nouveau_fifo_engine { +- void *priv; +- + int channels; + ++ struct nouveau_gpuobj_ref *playlist[2]; ++ int cur_playlist; ++ + int (*init)(struct drm_device *); + void (*takedown)(struct drm_device *); + +@@ -339,10 +331,11 @@ struct nouveau_pgraph_object_class { + struct nouveau_pgraph_engine { + struct nouveau_pgraph_object_class *grclass; + bool accel_blocked; +- void *ctxprog; +- void *ctxvals; + int grctx_size; + ++ /* NV2x/NV3x context table (0x400780) */ ++ struct nouveau_gpuobj_ref *ctx_table; ++ + int (*init)(struct drm_device *); + void (*takedown)(struct drm_device *); + +@@ -500,11 +493,6 @@ enum nouveau_card_type { + + struct drm_nouveau_private { + struct drm_device *dev; +- enum { +- NOUVEAU_CARD_INIT_DOWN, +- NOUVEAU_CARD_INIT_DONE, +- NOUVEAU_CARD_INIT_FAILED +- } init_state; + + /* the card type, takes NV_* as values */ + enum nouveau_card_type card_type; +@@ -533,8 +521,6 @@ struct drm_nouveau_private { + atomic_t validate_sequence; + } ttm; + +- struct fb_info *fbdev_info; +- + int fifo_alloc_count; + struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; + +@@ -595,11 +581,7 @@ struct drm_nouveau_private { + struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; + int vm_vram_pt_nr; + +- struct mem_block *ramin_heap; +- +- /* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */ +- uint32_t ctx_table_size; +- struct nouveau_gpuobj_ref *ctx_table; ++ struct drm_mm ramin_heap; + + struct list_head gpuobj_list; + +@@ -618,6 +600,11 @@ struct drm_nouveau_private { + struct backlight_device *backlight; + + struct nouveau_channel *evo; ++ struct { ++ struct dcb_entry *dcb; ++ u16 script; ++ u32 pclk; ++ } evo_irq; + + struct { + struct dentry *channel_root; +@@ -652,14 +639,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) + return 0; + } + +-#define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \ +- struct drm_nouveau_private *nv = dev->dev_private; \ +- if (nv->init_state != NOUVEAU_CARD_INIT_DONE) { \ +- NV_ERROR(dev, "called without init\n"); \ +- return -EINVAL; \ +- } \ +-} while (0) +- + #define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \ + struct drm_nouveau_private *nv = dev->dev_private; \ + if (!nouveau_channel_owner(dev, (cl), (id))) { \ +@@ -682,7 +661,6 @@ extern int nouveau_tv_disable; + extern char *nouveau_tv_norm; + extern int nouveau_reg_debug; + extern char *nouveau_vbios; +-extern int nouveau_ctxfw; + extern int nouveau_ignorelid; + extern int nouveau_nofbaccel; + extern int nouveau_noaccel; +@@ -707,15 +685,7 @@ extern bool nouveau_wait_for_idle(struct drm_device *); + extern int nouveau_card_init(struct drm_device *); + + /* nouveau_mem.c */ +-extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start, +- uint64_t size); +-extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, +- uint64_t size, int align2, +- struct drm_file *, int tail); +-extern void nouveau_mem_takedown(struct mem_block **heap); +-extern void nouveau_mem_free_block(struct mem_block *); + extern int nouveau_mem_detect(struct drm_device *dev); +-extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); + extern int nouveau_mem_init(struct drm_device *); + extern int nouveau_mem_init_agp(struct drm_device *); + extern void nouveau_mem_close(struct drm_device *); +@@ -857,11 +827,13 @@ void nouveau_register_dsm_handler(void); + void nouveau_unregister_dsm_handler(void); + int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); + bool nouveau_acpi_rom_supported(struct pci_dev *pdev); ++int nouveau_acpi_edid(struct drm_device *, struct drm_connector *); + #else + static inline void nouveau_register_dsm_handler(void) {} + static inline void nouveau_unregister_dsm_handler(void) {} + static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } + static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } ++static inline int nouveau_acpi_edid(struct drm_device *, struct drm_connector *) { return -EINVAL; } + #endif + + /* nouveau_backlight.c */ +@@ -1035,12 +1007,6 @@ extern int nv50_graph_unload_context(struct drm_device *); + extern void nv50_graph_context_switch(struct drm_device *); + extern int nv50_grctx_init(struct nouveau_grctx *); + +-/* nouveau_grctx.c */ +-extern int nouveau_grctx_prog_load(struct drm_device *); +-extern void nouveau_grctx_vals_load(struct drm_device *, +- struct nouveau_gpuobj *); +-extern void nouveau_grctx_fini(struct drm_device *); +- + /* nv04_instmem.c */ + extern int nv04_instmem_init(struct drm_device *); + extern void nv04_instmem_takedown(struct drm_device *); +@@ -1051,8 +1017,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, + extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); + extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); + extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); +-extern void nv04_instmem_prepare_access(struct drm_device *, bool write); +-extern void nv04_instmem_finish_access(struct drm_device *); ++extern void nv04_instmem_flush(struct drm_device *); + + /* nv50_instmem.c */ + extern int nv50_instmem_init(struct drm_device *); +@@ -1064,8 +1029,9 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, + extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); + extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); + extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); +-extern void nv50_instmem_prepare_access(struct drm_device *, bool write); +-extern void nv50_instmem_finish_access(struct drm_device *); ++extern void nv50_instmem_flush(struct drm_device *); ++extern void nv84_instmem_flush(struct drm_device *); ++extern void nv50_vm_flush(struct drm_device *, int engine); + + /* nv04_mc.c */ + extern int nv04_mc_init(struct drm_device *); +@@ -1088,13 +1054,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); + + /* nv04_dac.c */ +-extern int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry); ++extern int nv04_dac_create(struct drm_connector *, struct dcb_entry *); + extern uint32_t nv17_dac_sample_load(struct drm_encoder *encoder); + extern int nv04_dac_output_offset(struct drm_encoder *encoder); + extern void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable); ++extern bool nv04_dac_in_use(struct drm_encoder *encoder); + + /* nv04_dfp.c */ +-extern int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry); ++extern int nv04_dfp_create(struct drm_connector *, struct dcb_entry *); + extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent); + extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent, + int head, bool dl); +@@ -1103,10 +1070,10 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); + + /* nv04_tv.c */ + extern int nv04_tv_identify(struct drm_device *dev, int i2c_index); +-extern int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry); ++extern int nv04_tv_create(struct drm_connector *, struct dcb_entry *); + + /* nv17_tv.c */ +-extern int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry); ++extern int nv17_tv_create(struct drm_connector *, struct dcb_entry *); + + /* nv04_display.c */ + extern int nv04_display_create(struct drm_device *); +@@ -1147,7 +1114,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); + extern int nouveau_fence_flush(void *obj, void *arg); + extern void nouveau_fence_unref(void **obj); + extern void *nouveau_fence_ref(void *obj); +-extern void nouveau_fence_handler(struct drm_device *dev, int channel); + + /* nouveau_gem.c */ + extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, +diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h +index e1df820..a1a0d48 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h ++++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h +@@ -38,13 +38,15 @@ struct nouveau_encoder { + struct dcb_entry *dcb; + int or; + ++ /* different to drm_encoder.crtc, this reflects what's ++ * actually programmed on the hw, not the proposed crtc */ ++ struct drm_crtc *crtc; ++ + struct drm_display_mode mode; + int last_dpms; + + struct nv04_output_reg restore; + +- void (*disconnect)(struct nouveau_encoder *encoder); +- + union { + struct { + int mc_unknown; +@@ -71,8 +73,8 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc) + + struct nouveau_connector * + nouveau_encoder_connector_get(struct nouveau_encoder *encoder); +-int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry); +-int nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry); ++int nv50_sor_create(struct drm_connector *, struct dcb_entry *); ++int nv50_dac_create(struct drm_connector *, struct dcb_entry *); + + struct bit_displayport_encoder_table { + uint32_t match; +diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c +index 257ea13..2fb2444 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c ++++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c +@@ -333,7 +333,7 @@ nouveau_fbcon_output_poll_changed(struct drm_device *dev) + drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper); + } + +-int ++static int + nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev) + { + struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb; +diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c +index faddf53..813d853 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_fence.c ++++ b/drivers/gpu/drm/nouveau/nouveau_fence.c +@@ -67,12 +67,13 @@ nouveau_fence_update(struct nouveau_channel *chan) + if (USE_REFCNT) + sequence = nvchan_rd32(chan, 0x48); + else +- sequence = chan->fence.last_sequence_irq; ++ sequence = atomic_read(&chan->fence.last_sequence_irq); + + if (chan->fence.sequence_ack == sequence) + return; + chan->fence.sequence_ack = sequence; + ++ spin_lock(&chan->fence.lock); + list_for_each_safe(entry, tmp, &chan->fence.pending) { + fence = list_entry(entry, struct nouveau_fence, entry); + +@@ -84,6 +85,7 @@ nouveau_fence_update(struct nouveau_channel *chan) + if (sequence == chan->fence.sequence_ack) + break; + } ++ spin_unlock(&chan->fence.lock); + } + + int +@@ -119,7 +121,6 @@ nouveau_fence_emit(struct nouveau_fence *fence) + { + struct drm_nouveau_private *dev_priv = fence->channel->dev->dev_private; + struct nouveau_channel *chan = fence->channel; +- unsigned long flags; + int ret; + + ret = RING_SPACE(chan, 2); +@@ -127,9 +128,7 @@ nouveau_fence_emit(struct nouveau_fence *fence) + return ret; + + if (unlikely(chan->fence.sequence == chan->fence.sequence_ack - 1)) { +- spin_lock_irqsave(&chan->fence.lock, flags); + nouveau_fence_update(chan); +- spin_unlock_irqrestore(&chan->fence.lock, flags); + + BUG_ON(chan->fence.sequence == + chan->fence.sequence_ack - 1); +@@ -138,9 +137,9 @@ nouveau_fence_emit(struct nouveau_fence *fence) + fence->sequence = ++chan->fence.sequence; + + kref_get(&fence->refcount); +- spin_lock_irqsave(&chan->fence.lock, flags); ++ spin_lock(&chan->fence.lock); + list_add_tail(&fence->entry, &chan->fence.pending); +- spin_unlock_irqrestore(&chan->fence.lock, flags); ++ spin_unlock(&chan->fence.lock); + + BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1); + OUT_RING(chan, fence->sequence); +@@ -173,14 +172,11 @@ nouveau_fence_signalled(void *sync_obj, void *sync_arg) + { + struct nouveau_fence *fence = nouveau_fence(sync_obj); + struct nouveau_channel *chan = fence->channel; +- unsigned long flags; + + if (fence->signalled) + return true; + +- spin_lock_irqsave(&chan->fence.lock, flags); + nouveau_fence_update(chan); +- spin_unlock_irqrestore(&chan->fence.lock, flags); + return fence->signalled; + } + +@@ -221,27 +217,12 @@ nouveau_fence_flush(void *sync_obj, void *sync_arg) + return 0; + } + +-void +-nouveau_fence_handler(struct drm_device *dev, int channel) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *chan = NULL; +- +- if (channel >= 0 && channel < dev_priv->engine.fifo.channels) +- chan = dev_priv->fifos[channel]; +- +- if (chan) { +- spin_lock_irq(&chan->fence.lock); +- nouveau_fence_update(chan); +- spin_unlock_irq(&chan->fence.lock); +- } +-} +- + int + nouveau_fence_init(struct nouveau_channel *chan) + { + INIT_LIST_HEAD(&chan->fence.pending); + spin_lock_init(&chan->fence.lock); ++ atomic_set(&chan->fence.last_sequence_irq, 0); + return 0; + } + +diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c +index 69c76cf..547f2c2 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_gem.c ++++ b/drivers/gpu/drm/nouveau/nouveau_gem.c +@@ -137,8 +137,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, + uint32_t flags = 0; + int ret = 0; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; +- + if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL)) + dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping; + +@@ -577,10 +575,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, + struct drm_nouveau_gem_pushbuf_bo *bo; + struct nouveau_channel *chan; + struct validate_op op; +- struct nouveau_fence *fence = 0; ++ struct nouveau_fence *fence = NULL; + int i, j, ret = 0, do_reloc = 0; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan); + + req->vram_available = dev_priv->fb_aper_free; +@@ -760,8 +757,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, + bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT); + int ret = -EINVAL; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; +- + gem = drm_gem_object_lookup(dev, file_priv, req->handle); + if (!gem) + return ret; +@@ -800,8 +795,6 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data, + struct nouveau_bo *nvbo; + int ret = -EINVAL; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; +- + gem = drm_gem_object_lookup(dev, file_priv, req->handle); + if (!gem) + return ret; +@@ -827,8 +820,6 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data, + struct drm_gem_object *gem; + int ret; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; +- + gem = drm_gem_object_lookup(dev, file_priv, req->handle); + if (!gem) + return -EINVAL; +diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c +deleted file mode 100644 +index f731c5f..0000000 +--- a/drivers/gpu/drm/nouveau/nouveau_grctx.c ++++ /dev/null +@@ -1,160 +0,0 @@ +-/* +- * 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: Ben Skeggs +- */ +- +-#include <linux/firmware.h> +-#include <linux/slab.h> +- +-#include "drmP.h" +-#include "nouveau_drv.h" +- +-struct nouveau_ctxprog { +- uint32_t signature; +- uint8_t version; +- uint16_t length; +- uint32_t data[]; +-} __attribute__ ((packed)); +- +-struct nouveau_ctxvals { +- uint32_t signature; +- uint8_t version; +- uint32_t length; +- struct { +- uint32_t offset; +- uint32_t value; +- } data[]; +-} __attribute__ ((packed)); +- +-int +-nouveau_grctx_prog_load(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- const int chipset = dev_priv->chipset; +- const struct firmware *fw; +- const struct nouveau_ctxprog *cp; +- const struct nouveau_ctxvals *cv; +- char name[32]; +- int ret, i; +- +- if (pgraph->accel_blocked) +- return -ENODEV; +- +- if (!pgraph->ctxprog) { +- sprintf(name, "nouveau/nv%02x.ctxprog", chipset); +- ret = request_firmware(&fw, name, &dev->pdev->dev); +- if (ret) { +- NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset); +- return ret; +- } +- +- pgraph->ctxprog = kmemdup(fw->data, fw->size, GFP_KERNEL); +- if (!pgraph->ctxprog) { +- NV_ERROR(dev, "OOM copying ctxprog\n"); +- release_firmware(fw); +- return -ENOMEM; +- } +- +- cp = pgraph->ctxprog; +- if (le32_to_cpu(cp->signature) != 0x5043564e || +- cp->version != 0 || +- le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) { +- NV_ERROR(dev, "ctxprog invalid\n"); +- release_firmware(fw); +- nouveau_grctx_fini(dev); +- return -EINVAL; +- } +- release_firmware(fw); +- } +- +- if (!pgraph->ctxvals) { +- sprintf(name, "nouveau/nv%02x.ctxvals", chipset); +- ret = request_firmware(&fw, name, &dev->pdev->dev); +- if (ret) { +- NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset); +- nouveau_grctx_fini(dev); +- return ret; +- } +- +- pgraph->ctxvals = kmemdup(fw->data, fw->size, GFP_KERNEL); +- if (!pgraph->ctxvals) { +- NV_ERROR(dev, "OOM copying ctxvals\n"); +- release_firmware(fw); +- nouveau_grctx_fini(dev); +- return -ENOMEM; +- } +- +- cv = (void *)pgraph->ctxvals; +- if (le32_to_cpu(cv->signature) != 0x5643564e || +- cv->version != 0 || +- le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) { +- NV_ERROR(dev, "ctxvals invalid\n"); +- release_firmware(fw); +- nouveau_grctx_fini(dev); +- return -EINVAL; +- } +- release_firmware(fw); +- } +- +- cp = pgraph->ctxprog; +- +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); +- for (i = 0; i < le16_to_cpu(cp->length); i++) +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, +- le32_to_cpu(cp->data[i])); +- +- return 0; +-} +- +-void +-nouveau_grctx_fini(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- +- if (pgraph->ctxprog) { +- kfree(pgraph->ctxprog); +- pgraph->ctxprog = NULL; +- } +- +- if (pgraph->ctxvals) { +- kfree(pgraph->ctxprog); +- pgraph->ctxvals = NULL; +- } +-} +- +-void +-nouveau_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; +- struct nouveau_ctxvals *cv = pgraph->ctxvals; +- int i; +- +- if (!cv) +- return; +- +- for (i = 0; i < le32_to_cpu(cv->length); i++) +- nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset), +- le32_to_cpu(cv->data[i].value)); +-} +diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c +index 316a3c7..97ba89e 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c ++++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c +@@ -278,3 +278,37 @@ nouveau_i2c_find(struct drm_device *dev, int index) + return i2c->chan; + } + ++bool ++nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr) ++{ ++ struct i2c_msg msg = { ++ .addr = addr, ++ .len = 0, ++ }; ++ ++ return i2c_transfer(&i2c->adapter, &msg, 1) == 1; ++} ++ ++int ++nouveau_i2c_identify(struct drm_device *dev, const char *what, ++ struct i2c_board_info *info, int index) ++{ ++ struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index); ++ int was_locked, i; ++ ++ was_locked = NVLockVgaCrtcs(dev, false); ++ NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index); ++ ++ for (i = 0; info[i].addr; i++) { ++ if (nouveau_probe_i2c_addr(i2c, info[i].addr)) { ++ NV_INFO(dev, "Detected %s: %s\n", what, info[i].type); ++ goto out; ++ } ++ } ++ ++ NV_DEBUG(dev, "No devices found.\n"); ++out: ++ NVLockVgaCrtcs(dev, was_locked); ++ ++ return info[i].addr ? i : -ENODEV; ++} +diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h +index c8eaf7a..6dd2f87 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_i2c.h ++++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h +@@ -45,6 +45,9 @@ struct nouveau_i2c_chan { + int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index); + void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *); + struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index); ++bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr); ++int nouveau_i2c_identify(struct drm_device *dev, const char *what, ++ struct i2c_board_info *info, int index); + + int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, + uint8_t *read_byte); +diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c +index c1fd42b..adf5ac4 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_mem.c ++++ b/drivers/gpu/drm/nouveau/nouveau_mem.c +@@ -35,162 +35,6 @@ + #include "drm_sarea.h" + #include "nouveau_drv.h" + +-static struct mem_block * +-split_block(struct mem_block *p, uint64_t start, uint64_t size, +- struct drm_file *file_priv) +-{ +- /* Maybe cut off the start of an existing block */ +- if (start > p->start) { +- struct mem_block *newblock = +- kmalloc(sizeof(*newblock), GFP_KERNEL); +- if (!newblock) +- goto out; +- newblock->start = start; +- newblock->size = p->size - (start - p->start); +- newblock->file_priv = NULL; +- newblock->next = p->next; +- newblock->prev = p; +- p->next->prev = newblock; +- p->next = newblock; +- p->size -= newblock->size; +- p = newblock; +- } +- +- /* Maybe cut off the end of an existing block */ +- if (size < p->size) { +- struct mem_block *newblock = +- kmalloc(sizeof(*newblock), GFP_KERNEL); +- if (!newblock) +- goto out; +- newblock->start = start + size; +- newblock->size = p->size - size; +- newblock->file_priv = NULL; +- newblock->next = p->next; +- newblock->prev = p; +- p->next->prev = newblock; +- p->next = newblock; +- p->size = size; +- } +- +-out: +- /* Our block is in the middle */ +- p->file_priv = file_priv; +- return p; +-} +- +-struct mem_block * +-nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size, +- int align2, struct drm_file *file_priv, int tail) +-{ +- struct mem_block *p; +- uint64_t mask = (1 << align2) - 1; +- +- if (!heap) +- return NULL; +- +- if (tail) { +- list_for_each_prev(p, heap) { +- uint64_t start = ((p->start + p->size) - size) & ~mask; +- +- if (p->file_priv == NULL && start >= p->start && +- start + size <= p->start + p->size) +- return split_block(p, start, size, file_priv); +- } +- } else { +- list_for_each(p, heap) { +- uint64_t start = (p->start + mask) & ~mask; +- +- if (p->file_priv == NULL && +- start + size <= p->start + p->size) +- return split_block(p, start, size, file_priv); +- } +- } +- +- return NULL; +-} +- +-void nouveau_mem_free_block(struct mem_block *p) +-{ +- p->file_priv = NULL; +- +- /* Assumes a single contiguous range. Needs a special file_priv in +- * 'heap' to stop it being subsumed. +- */ +- if (p->next->file_priv == NULL) { +- struct mem_block *q = p->next; +- p->size += q->size; +- p->next = q->next; +- p->next->prev = p; +- kfree(q); +- } +- +- if (p->prev->file_priv == NULL) { +- struct mem_block *q = p->prev; +- q->size += p->size; +- q->next = p->next; +- q->next->prev = q; +- kfree(p); +- } +-} +- +-/* Initialize. How to check for an uninitialized heap? +- */ +-int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start, +- uint64_t size) +-{ +- struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL); +- +- if (!blocks) +- return -ENOMEM; +- +- *heap = kmalloc(sizeof(**heap), GFP_KERNEL); +- if (!*heap) { +- kfree(blocks); +- return -ENOMEM; +- } +- +- blocks->start = start; +- blocks->size = size; +- blocks->file_priv = NULL; +- blocks->next = blocks->prev = *heap; +- +- memset(*heap, 0, sizeof(**heap)); +- (*heap)->file_priv = (struct drm_file *) -1; +- (*heap)->next = (*heap)->prev = blocks; +- return 0; +-} +- +-/* +- * Free all blocks associated with the releasing file_priv +- */ +-void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap) +-{ +- struct mem_block *p; +- +- if (!heap || !heap->next) +- return; +- +- list_for_each(p, heap) { +- if (p->file_priv == file_priv) +- p->file_priv = NULL; +- } +- +- /* Assumes a single contiguous range. Needs a special file_priv in +- * 'heap' to stop it being subsumed. +- */ +- list_for_each(p, heap) { +- while ((p->file_priv == NULL) && +- (p->next->file_priv == NULL) && +- (p->next != heap)) { +- struct mem_block *q = p->next; +- p->size += q->size; +- p->next = q->next; +- p->next->prev = p; +- kfree(q); +- } +- } +-} +- + /* + * NV10-NV40 tiling helpers + */ +@@ -299,7 +143,6 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, + phys |= 0x30; + } + +- dev_priv->engine.instmem.prepare_access(dev, true); + while (size) { + unsigned offset_h = upper_32_bits(phys); + unsigned offset_l = lower_32_bits(phys); +@@ -331,36 +174,12 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, + } + } + } +- dev_priv->engine.instmem.finish_access(dev); +- +- nv_wr32(dev, 0x100c80, 0x00050001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } +- +- nv_wr32(dev, 0x100c80, 0x00000001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } +- +- nv_wr32(dev, 0x100c80, 0x00040001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } +- +- nv_wr32(dev, 0x100c80, 0x00060001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } ++ dev_priv->engine.instmem.flush(dev); + ++ nv50_vm_flush(dev, 5); ++ nv50_vm_flush(dev, 0); ++ nv50_vm_flush(dev, 4); ++ nv50_vm_flush(dev, 6); + return 0; + } + +@@ -374,7 +193,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) + virt -= dev_priv->vm_vram_base; + pages = (size >> 16) << 1; + +- dev_priv->engine.instmem.prepare_access(dev, true); + while (pages) { + pgt = dev_priv->vm_vram_pt[virt >> 29]; + pte = (virt & 0x1ffe0000ULL) >> 15; +@@ -388,57 +206,19 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) + while (pte < end) + nv_wo32(dev, pgt, pte++, 0); + } +- dev_priv->engine.instmem.finish_access(dev); +- +- nv_wr32(dev, 0x100c80, 0x00050001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- return; +- } +- +- nv_wr32(dev, 0x100c80, 0x00000001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- return; +- } +- +- nv_wr32(dev, 0x100c80, 0x00040001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- return; +- } ++ dev_priv->engine.instmem.flush(dev); + +- nv_wr32(dev, 0x100c80, 0x00060001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- } ++ nv50_vm_flush(dev, 5); ++ nv50_vm_flush(dev, 0); ++ nv50_vm_flush(dev, 4); ++ nv50_vm_flush(dev, 6); + } + + /* + * Cleanup everything + */ +-void nouveau_mem_takedown(struct mem_block **heap) +-{ +- struct mem_block *p; +- +- if (!*heap) +- return; +- +- for (p = (*heap)->next; p != *heap;) { +- struct mem_block *q = p; +- p = p->next; +- kfree(q); +- } +- +- kfree(*heap); +- *heap = NULL; +-} +- +-void nouveau_mem_close(struct drm_device *dev) ++void ++nouveau_mem_close(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + +@@ -449,8 +229,7 @@ void nouveau_mem_close(struct drm_device *dev) + + nouveau_ttm_global_release(dev_priv); + +- if (drm_core_has_AGP(dev) && dev->agp && +- drm_core_check_feature(dev, DRIVER_MODESET)) { ++ if (drm_core_has_AGP(dev) && dev->agp) { + struct drm_agp_mem *entry, *tempe; + + /* Remove AGP resources, but leave dev->agp +@@ -470,29 +249,29 @@ void nouveau_mem_close(struct drm_device *dev) + dev->agp->enabled = 0; + } + +- if (dev_priv->fb_mtrr) { ++ if (dev_priv->fb_mtrr >= 0) { + drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1), + drm_get_resource_len(dev, 1), DRM_MTRR_WC); +- dev_priv->fb_mtrr = 0; ++ dev_priv->fb_mtrr = -1; + } + } + + static uint32_t + nouveau_mem_detect_nv04(struct drm_device *dev) + { +- uint32_t boot0 = nv_rd32(dev, NV03_BOOT_0); ++ uint32_t boot0 = nv_rd32(dev, NV04_PFB_BOOT_0); + + if (boot0 & 0x00000100) + return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024; + +- switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) { +- case NV04_BOOT_0_RAM_AMOUNT_32MB: ++ switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) { ++ case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB: + return 32 * 1024 * 1024; +- case NV04_BOOT_0_RAM_AMOUNT_16MB: ++ case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB: + return 16 * 1024 * 1024; +- case NV04_BOOT_0_RAM_AMOUNT_8MB: ++ case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB: + return 8 * 1024 * 1024; +- case NV04_BOOT_0_RAM_AMOUNT_4MB: ++ case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB: + return 4 * 1024 * 1024; + } + +@@ -536,12 +315,18 @@ nouveau_mem_detect(struct drm_device *dev) + } else + if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) { + dev_priv->vram_size = nouveau_mem_detect_nforce(dev); ++ } else ++ if (dev_priv->card_type < NV_50) { ++ dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); ++ dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; + } else { +- dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA); +- dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK; +- if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) ++ dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); ++ dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; ++ dev_priv->vram_size &= 0xffffffff00ll; ++ if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) { + dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); + dev_priv->vram_sys_base <<= 12; ++ } + } + + NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); +diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c +index 9537f3e..3ec181f 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c ++++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c +@@ -55,7 +55,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) + if (ret) + goto out_err; + +- ret = nouveau_mem_init_heap(&chan->notifier_heap, 0, ntfy->bo.mem.size); ++ ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size); + if (ret) + goto out_err; + +@@ -80,7 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan) + nouveau_bo_unpin(chan->notifier_bo); + mutex_unlock(&dev->struct_mutex); + drm_gem_object_unreference_unlocked(chan->notifier_bo->gem); +- nouveau_mem_takedown(&chan->notifier_heap); ++ drm_mm_takedown(&chan->notifier_heap); + } + + static void +@@ -90,7 +90,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev, + NV_DEBUG(dev, "\n"); + + if (gpuobj->priv) +- nouveau_mem_free_block(gpuobj->priv); ++ drm_mm_put_block(gpuobj->priv); + } + + int +@@ -100,18 +100,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *nobj = NULL; +- struct mem_block *mem; ++ struct drm_mm_node *mem; + uint32_t offset; + int target, ret; + +- if (!chan->notifier_heap) { +- NV_ERROR(dev, "Channel %d doesn't have a notifier heap!\n", +- chan->id); +- return -EINVAL; +- } +- +- mem = nouveau_mem_alloc_block(chan->notifier_heap, size, 0, +- (struct drm_file *)-2, 0); ++ mem = drm_mm_search_free(&chan->notifier_heap, size, 0, 0); ++ if (mem) ++ mem = drm_mm_get_block(mem, size, 0); + if (!mem) { + NV_ERROR(dev, "Channel %d notifier block full\n", chan->id); + return -ENOMEM; +@@ -144,17 +139,17 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, + mem->size, NV_DMA_ACCESS_RW, target, + &nobj); + if (ret) { +- nouveau_mem_free_block(mem); ++ drm_mm_put_block(mem); + NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret); + return ret; + } +- nobj->dtor = nouveau_notifier_gpuobj_dtor; +- nobj->priv = mem; ++ nobj->dtor = nouveau_notifier_gpuobj_dtor; ++ nobj->priv = mem; + + ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL); + if (ret) { + nouveau_gpuobj_del(dev, &nobj); +- nouveau_mem_free_block(mem); ++ drm_mm_put_block(mem); + NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret); + return ret; + } +@@ -170,7 +165,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset) + return -EINVAL; + + if (poffset) { +- struct mem_block *mem = nobj->priv; ++ struct drm_mm_node *mem = nobj->priv; + + if (*poffset >= mem->size) + return false; +@@ -189,7 +184,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, + struct nouveau_channel *chan; + int ret; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan); + + ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset); +diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c +index e7c100b..4bf6b33 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_object.c ++++ b/drivers/gpu/drm/nouveau/nouveau_object.c +@@ -132,7 +132,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) + } + } + +- instmem->prepare_access(dev, true); + co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); + do { + if (!nouveau_ramht_entry_valid(dev, ramht, co)) { +@@ -143,7 +142,7 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) + nv_wo32(dev, ramht, (co + 4)/4, ctx); + + list_add_tail(&ref->list, &chan->ramht_refs); +- instmem->finish_access(dev); ++ instmem->flush(dev); + return 0; + } + NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n", +@@ -153,7 +152,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) + if (co >= dev_priv->ramht_size) + co = 0; + } while (co != ho); +- instmem->finish_access(dev); + + NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id); + return -ENOMEM; +@@ -173,7 +171,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) + return; + } + +- instmem->prepare_access(dev, true); + co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); + do { + if (nouveau_ramht_entry_valid(dev, ramht, co) && +@@ -186,7 +183,7 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) + nv_wo32(dev, ramht, (co + 4)/4, 0x00000000); + + list_del(&ref->list); +- instmem->finish_access(dev); ++ instmem->flush(dev); + return; + } + +@@ -195,7 +192,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) + co = 0; + } while (co != ho); + list_del(&ref->list); +- instmem->finish_access(dev); + + NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", + chan->id, ref->handle); +@@ -209,7 +205,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine *engine = &dev_priv->engine; + struct nouveau_gpuobj *gpuobj; +- struct mem_block *pramin = NULL; ++ struct drm_mm *pramin = NULL; + int ret; + + NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n", +@@ -233,25 +229,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, + * available. + */ + if (chan) { +- if (chan->ramin_heap) { +- NV_DEBUG(dev, "private heap\n"); +- pramin = chan->ramin_heap; +- } else +- if (dev_priv->card_type < NV_50) { +- NV_DEBUG(dev, "global heap fallback\n"); +- pramin = dev_priv->ramin_heap; +- } ++ NV_DEBUG(dev, "channel heap\n"); ++ pramin = &chan->ramin_heap; + } else { + NV_DEBUG(dev, "global heap\n"); +- pramin = dev_priv->ramin_heap; +- } +- +- if (!pramin) { +- NV_ERROR(dev, "No PRAMIN heap!\n"); +- return -EINVAL; +- } ++ pramin = &dev_priv->ramin_heap; + +- if (!chan) { + ret = engine->instmem.populate(dev, gpuobj, &size); + if (ret) { + nouveau_gpuobj_del(dev, &gpuobj); +@@ -260,9 +243,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, + } + + /* Allocate a chunk of the PRAMIN aperture */ +- gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, +- drm_order(align), +- (struct drm_file *)-2, 0); ++ gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0); ++ if (gpuobj->im_pramin) ++ gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align); ++ + if (!gpuobj->im_pramin) { + nouveau_gpuobj_del(dev, &gpuobj); + return -ENOMEM; +@@ -279,10 +263,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, + if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { + int i; + +- engine->instmem.prepare_access(dev, true); + for (i = 0; i < gpuobj->im_pramin->size; i += 4) + nv_wo32(dev, gpuobj, i/4, 0); +- engine->instmem.finish_access(dev); ++ engine->instmem.flush(dev); + } + + *gpuobj_ret = gpuobj; +@@ -370,10 +353,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) + } + + if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) { +- engine->instmem.prepare_access(dev, true); + for (i = 0; i < gpuobj->im_pramin->size; i += 4) + nv_wo32(dev, gpuobj, i/4, 0); +- engine->instmem.finish_access(dev); ++ engine->instmem.flush(dev); + } + + if (gpuobj->dtor) +@@ -386,7 +368,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) + if (gpuobj->flags & NVOBJ_FLAG_FAKE) + kfree(gpuobj->im_pramin); + else +- nouveau_mem_free_block(gpuobj->im_pramin); ++ drm_mm_put_block(gpuobj->im_pramin); + } + + list_del(&gpuobj->list); +@@ -589,7 +571,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, + list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); + + if (p_offset != ~0) { +- gpuobj->im_pramin = kzalloc(sizeof(struct mem_block), ++ gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node), + GFP_KERNEL); + if (!gpuobj->im_pramin) { + nouveau_gpuobj_del(dev, &gpuobj); +@@ -605,10 +587,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, + } + + if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { +- dev_priv->engine.instmem.prepare_access(dev, true); + for (i = 0; i < gpuobj->im_pramin->size; i += 4) + nv_wo32(dev, gpuobj, i/4, 0); +- dev_priv->engine.instmem.finish_access(dev); ++ dev_priv->engine.instmem.flush(dev); + } + + if (pref) { +@@ -696,8 +677,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, + return ret; + } + +- instmem->prepare_access(dev, true); +- + if (dev_priv->card_type < NV_50) { + uint32_t frame, adjust, pte_flags = 0; + +@@ -734,7 +713,7 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, + nv_wo32(dev, *gpuobj, 5, flags5); + } + +- instmem->finish_access(dev); ++ instmem->flush(dev); + + (*gpuobj)->engine = NVOBJ_ENGINE_SW; + (*gpuobj)->class = class; +@@ -849,7 +828,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, + return ret; + } + +- dev_priv->engine.instmem.prepare_access(dev, true); + if (dev_priv->card_type >= NV_50) { + nv_wo32(dev, *gpuobj, 0, class); + nv_wo32(dev, *gpuobj, 5, 0x00010000); +@@ -874,7 +852,7 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, + } + } + } +- dev_priv->engine.instmem.finish_access(dev); ++ dev_priv->engine.instmem.flush(dev); + + (*gpuobj)->engine = NVOBJ_ENGINE_GR; + (*gpuobj)->class = class; +@@ -920,6 +898,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) + base = 0; + + /* PGRAPH context */ ++ size += dev_priv->engine.graph.grctx_size; + + if (dev_priv->card_type == NV_50) { + /* Various fixed table thingos */ +@@ -930,12 +909,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) + size += 0x8000; + /* RAMFC */ + size += 0x1000; +- /* PGRAPH context */ +- size += 0x70000; + } + +- NV_DEBUG(dev, "ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n", +- chan->id, size, base); + ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0, + &chan->ramin); + if (ret) { +@@ -944,8 +919,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) + } + pramin = chan->ramin->gpuobj; + +- ret = nouveau_mem_init_heap(&chan->ramin_heap, +- pramin->im_pramin->start + base, size); ++ ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size); + if (ret) { + NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret); + nouveau_gpuobj_ref_del(dev, &chan->ramin); +@@ -969,15 +943,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + + NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); + +- /* Reserve a block of PRAMIN for the channel +- *XXX: maybe on <NV50 too at some point +- */ +- if (0 || dev_priv->card_type == NV_50) { +- ret = nouveau_gpuobj_channel_init_pramin(chan); +- if (ret) { +- NV_ERROR(dev, "init pramin\n"); +- return ret; +- } ++ /* Allocate a chunk of memory for per-channel object storage */ ++ ret = nouveau_gpuobj_channel_init_pramin(chan); ++ if (ret) { ++ NV_ERROR(dev, "init pramin\n"); ++ return ret; + } + + /* NV50 VM +@@ -988,17 +958,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + if (dev_priv->card_type >= NV_50) { + uint32_t vm_offset, pde; + +- instmem->prepare_access(dev, true); +- + vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200; + vm_offset += chan->ramin->gpuobj->im_pramin->start; + + ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000, + 0, &chan->vm_pd, NULL); +- if (ret) { +- instmem->finish_access(dev); ++ if (ret) + return ret; +- } + for (i = 0; i < 0x4000; i += 8) { + nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000); + nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe); +@@ -1008,10 +974,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + ret = nouveau_gpuobj_ref_add(dev, NULL, 0, + dev_priv->gart_info.sg_ctxdma, + &chan->vm_gart_pt); +- if (ret) { +- instmem->finish_access(dev); ++ if (ret) + return ret; +- } + nv_wo32(dev, chan->vm_pd, pde++, + chan->vm_gart_pt->instance | 0x03); + nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); +@@ -1021,17 +985,15 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, + ret = nouveau_gpuobj_ref_add(dev, NULL, 0, + dev_priv->vm_vram_pt[i], + &chan->vm_vram_pt[i]); +- if (ret) { +- instmem->finish_access(dev); ++ if (ret) + return ret; +- } + + nv_wo32(dev, chan->vm_pd, pde++, + chan->vm_vram_pt[i]->instance | 0x61); + nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); + } + +- instmem->finish_access(dev); ++ instmem->flush(dev); + } + + /* RAMHT */ +@@ -1130,8 +1092,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) + for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) + nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]); + +- if (chan->ramin_heap) +- nouveau_mem_takedown(&chan->ramin_heap); ++ if (chan->ramin_heap.fl_entry.next) ++ drm_mm_takedown(&chan->ramin_heap); + if (chan->ramin) + nouveau_gpuobj_ref_del(dev, &chan->ramin); + +@@ -1164,10 +1126,8 @@ nouveau_gpuobj_suspend(struct drm_device *dev) + return -ENOMEM; + } + +- dev_priv->engine.instmem.prepare_access(dev, false); + for (i = 0; i < gpuobj->im_pramin->size / 4; i++) + gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i); +- dev_priv->engine.instmem.finish_access(dev); + } + + return 0; +@@ -1212,10 +1172,9 @@ nouveau_gpuobj_resume(struct drm_device *dev) + if (!gpuobj->im_backing_suspend) + continue; + +- dev_priv->engine.instmem.prepare_access(dev, true); + for (i = 0; i < gpuobj->im_pramin->size / 4; i++) + nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]); +- dev_priv->engine.instmem.finish_access(dev); ++ dev_priv->engine.instmem.flush(dev); + } + + nouveau_gpuobj_suspend_cleanup(dev); +@@ -1232,7 +1191,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, + struct nouveau_channel *chan; + int ret; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan); + + if (init->handle == ~0) +@@ -1283,7 +1241,6 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, + struct nouveau_channel *chan; + int ret; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan); + + ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref); +diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h +index 6ca80a3..9c1056c 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_reg.h ++++ b/drivers/gpu/drm/nouveau/nouveau_reg.h +@@ -1,19 +1,64 @@ + ++#define NV04_PFB_BOOT_0 0x00100000 ++# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 ++# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 ++# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 ++# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 ++# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 ++# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004 ++# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028 ++# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000 ++# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008 ++# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010 ++# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018 ++# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020 ++# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028 ++# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100 ++# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000 ++#define NV04_PFB_DEBUG_0 0x00100080 ++# define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001 ++# define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010 ++# define NV04_PFB_DEBUG_0_REFRESH_COUNTX64 0x00003f00 ++# define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK 0x00004000 ++# define NV04_PFB_DEBUG_0_SAFE_MODE 0x00008000 ++# define NV04_PFB_DEBUG_0_ALOM_ENABLE 0x00010000 ++# define NV04_PFB_DEBUG_0_CASOE 0x00100000 ++# define NV04_PFB_DEBUG_0_CKE_INVERT 0x10000000 ++# define NV04_PFB_DEBUG_0_REFINC 0x20000000 ++# define NV04_PFB_DEBUG_0_SAVE_POWER_OFF 0x40000000 ++#define NV04_PFB_CFG0 0x00100200 ++# define NV04_PFB_CFG0_SCRAMBLE 0x20000000 ++#define NV04_PFB_CFG1 0x00100204 ++#define NV04_PFB_FIFO_DATA 0x0010020c ++# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000 ++# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20 ++#define NV10_PFB_REFCTRL 0x00100210 ++# define NV10_PFB_REFCTRL_VALID_1 (1 << 31) ++#define NV04_PFB_PAD 0x0010021c ++# define NV04_PFB_PAD_CKE_NORMAL (1 << 0) ++#define NV10_PFB_TILE(i) (0x00100240 + (i*16)) ++#define NV10_PFB_TILE__SIZE 8 ++#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16)) ++#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16)) ++#define NV10_PFB_TSTATUS(i) (0x0010024c + (i*16)) ++#define NV04_PFB_REF 0x001002d0 ++# define NV04_PFB_REF_CMD_REFRESH (1 << 0) ++#define NV04_PFB_PRE 0x001002d4 ++# define NV04_PFB_PRE_CMD_PRECHARGE (1 << 0) ++#define NV10_PFB_CLOSE_PAGE2 0x0010033c ++#define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i)) ++#define NV40_PFB_TILE(i) (0x00100600 + (i*16)) ++#define NV40_PFB_TILE__SIZE_0 12 ++#define NV40_PFB_TILE__SIZE_1 15 ++#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16)) ++#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16)) ++#define NV40_PFB_TSTATUS(i) (0x0010060c + (i*16)) ++#define NV40_PFB_UNK_800 0x00100800 + +-#define NV03_BOOT_0 0x00100000 +-# define NV03_BOOT_0_RAM_AMOUNT 0x00000003 +-# define NV03_BOOT_0_RAM_AMOUNT_8MB 0x00000000 +-# define NV03_BOOT_0_RAM_AMOUNT_2MB 0x00000001 +-# define NV03_BOOT_0_RAM_AMOUNT_4MB 0x00000002 +-# define NV03_BOOT_0_RAM_AMOUNT_8MB_SDRAM 0x00000003 +-# define NV04_BOOT_0_RAM_AMOUNT_32MB 0x00000000 +-# define NV04_BOOT_0_RAM_AMOUNT_4MB 0x00000001 +-# define NV04_BOOT_0_RAM_AMOUNT_8MB 0x00000002 +-# define NV04_BOOT_0_RAM_AMOUNT_16MB 0x00000003 +- +-#define NV04_FIFO_DATA 0x0010020c +-# define NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000 +-# define NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20 ++#define NV_PEXTDEV_BOOT_0 0x00101000 ++#define NV_PEXTDEV_BOOT_0_RAMCFG 0x0000003c ++# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12) ++#define NV_PEXTDEV_BOOT_3 0x0010100c + + #define NV_RAMIN 0x00700000 + +@@ -131,23 +176,6 @@ + #define NV04_PTIMER_TIME_1 0x00009410 + #define NV04_PTIMER_ALARM_0 0x00009420 + +-#define NV04_PFB_CFG0 0x00100200 +-#define NV04_PFB_CFG1 0x00100204 +-#define NV40_PFB_020C 0x0010020C +-#define NV10_PFB_TILE(i) (0x00100240 + (i*16)) +-#define NV10_PFB_TILE__SIZE 8 +-#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16)) +-#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16)) +-#define NV10_PFB_TSTATUS(i) (0x0010024C + (i*16)) +-#define NV10_PFB_CLOSE_PAGE2 0x0010033C +-#define NV40_PFB_TILE(i) (0x00100600 + (i*16)) +-#define NV40_PFB_TILE__SIZE_0 12 +-#define NV40_PFB_TILE__SIZE_1 15 +-#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16)) +-#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16)) +-#define NV40_PFB_TSTATUS(i) (0x0010060C + (i*16)) +-#define NV40_PFB_UNK_800 0x00100800 +- + #define NV04_PGRAPH_DEBUG_0 0x00400080 + #define NV04_PGRAPH_DEBUG_1 0x00400084 + #define NV04_PGRAPH_DEBUG_2 0x00400088 +@@ -814,6 +842,7 @@ + #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000 + #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff + #define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80) ++#define NV50_SOR_DP_CTRL_ENABLED 0x00000001 + #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000 + #define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000 + #define NV50_SOR_DP_CTRL_LANE_0_ENABLED 0x00010000 +diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +index 1d6ee8b..491767f 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c ++++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c +@@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) + + NV_DEBUG(dev, "pg=0x%lx\n", mem->mm_node->start); + +- dev_priv->engine.instmem.prepare_access(nvbe->dev, true); + pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT); + nvbe->pte_start = pte; + for (i = 0; i < nvbe->nr_pages; i++) { +@@ -116,24 +115,11 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) + dma_offset += NV_CTXDMA_PAGE_SIZE; + } + } +- dev_priv->engine.instmem.finish_access(nvbe->dev); ++ dev_priv->engine.instmem.flush(nvbe->dev); + + if (dev_priv->card_type == NV_50) { +- nv_wr32(dev, 0x100c80, 0x00050001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", +- nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } +- +- nv_wr32(dev, 0x100c80, 0x00000001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", +- nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } ++ nv50_vm_flush(dev, 5); /* PGRAPH */ ++ nv50_vm_flush(dev, 0); /* PFIFO */ + } + + nvbe->bound = true; +@@ -154,7 +140,6 @@ nouveau_sgdma_unbind(struct ttm_backend *be) + if (!nvbe->bound) + return 0; + +- dev_priv->engine.instmem.prepare_access(nvbe->dev, true); + pte = nvbe->pte_start; + for (i = 0; i < nvbe->nr_pages; i++) { + dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus; +@@ -170,24 +155,11 @@ nouveau_sgdma_unbind(struct ttm_backend *be) + dma_offset += NV_CTXDMA_PAGE_SIZE; + } + } +- dev_priv->engine.instmem.finish_access(nvbe->dev); ++ dev_priv->engine.instmem.flush(nvbe->dev); + + if (dev_priv->card_type == NV_50) { +- nv_wr32(dev, 0x100c80, 0x00050001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", +- nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } +- +- nv_wr32(dev, 0x100c80, 0x00000001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", +- nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } ++ nv50_vm_flush(dev, 5); ++ nv50_vm_flush(dev, 0); + } + + nvbe->bound = false; +@@ -272,7 +244,6 @@ nouveau_sgdma_init(struct drm_device *dev) + pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + +- dev_priv->engine.instmem.prepare_access(dev, true); + if (dev_priv->card_type < NV_50) { + /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and + * confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE +@@ -294,7 +265,7 @@ nouveau_sgdma_init(struct drm_device *dev) + nv_wo32(dev, gpuobj, (i+4)/4, 0); + } + } +- dev_priv->engine.instmem.finish_access(dev); ++ dev_priv->engine.instmem.flush(dev); + + dev_priv->gart_info.type = NOUVEAU_GART_SGDMA; + dev_priv->gart_info.aper_base = 0; +@@ -325,14 +296,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma; +- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; + int pte; + + pte = (offset >> NV_CTXDMA_PAGE_SHIFT); + if (dev_priv->card_type < NV_50) { +- instmem->prepare_access(dev, false); + *page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK; +- instmem->finish_access(dev); + return 0; + } + +diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c +index b02a231..621e080 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_state.c ++++ b/drivers/gpu/drm/nouveau/nouveau_state.c +@@ -54,8 +54,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; +- engine->instmem.prepare_access = nv04_instmem_prepare_access; +- engine->instmem.finish_access = nv04_instmem_finish_access; ++ engine->instmem.flush = nv04_instmem_flush; + engine->mc.init = nv04_mc_init; + engine->mc.takedown = nv04_mc_takedown; + engine->timer.init = nv04_timer_init; +@@ -95,8 +94,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; +- engine->instmem.prepare_access = nv04_instmem_prepare_access; +- engine->instmem.finish_access = nv04_instmem_finish_access; ++ engine->instmem.flush = nv04_instmem_flush; + engine->mc.init = nv04_mc_init; + engine->mc.takedown = nv04_mc_takedown; + engine->timer.init = nv04_timer_init; +@@ -138,8 +136,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; +- engine->instmem.prepare_access = nv04_instmem_prepare_access; +- engine->instmem.finish_access = nv04_instmem_finish_access; ++ engine->instmem.flush = nv04_instmem_flush; + engine->mc.init = nv04_mc_init; + engine->mc.takedown = nv04_mc_takedown; + engine->timer.init = nv04_timer_init; +@@ -181,8 +178,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; +- engine->instmem.prepare_access = nv04_instmem_prepare_access; +- engine->instmem.finish_access = nv04_instmem_finish_access; ++ engine->instmem.flush = nv04_instmem_flush; + engine->mc.init = nv04_mc_init; + engine->mc.takedown = nv04_mc_takedown; + engine->timer.init = nv04_timer_init; +@@ -225,8 +221,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->instmem.clear = nv04_instmem_clear; + engine->instmem.bind = nv04_instmem_bind; + engine->instmem.unbind = nv04_instmem_unbind; +- engine->instmem.prepare_access = nv04_instmem_prepare_access; +- engine->instmem.finish_access = nv04_instmem_finish_access; ++ engine->instmem.flush = nv04_instmem_flush; + engine->mc.init = nv40_mc_init; + engine->mc.takedown = nv40_mc_takedown; + engine->timer.init = nv04_timer_init; +@@ -271,8 +266,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) + engine->instmem.clear = nv50_instmem_clear; + engine->instmem.bind = nv50_instmem_bind; + engine->instmem.unbind = nv50_instmem_unbind; +- engine->instmem.prepare_access = nv50_instmem_prepare_access; +- engine->instmem.finish_access = nv50_instmem_finish_access; ++ if (dev_priv->chipset == 0x50) ++ engine->instmem.flush = nv50_instmem_flush; ++ else ++ engine->instmem.flush = nv84_instmem_flush; + engine->mc.init = nv50_mc_init; + engine->mc.takedown = nv50_mc_takedown; + engine->timer.init = nv04_timer_init; +@@ -407,11 +404,6 @@ nouveau_card_init(struct drm_device *dev) + struct nouveau_engine *engine; + int ret; + +- NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); +- +- if (dev_priv->init_state == NOUVEAU_CARD_INIT_DONE) +- return 0; +- + vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); + vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state, + nouveau_switcheroo_can_switch); +@@ -421,15 +413,12 @@ nouveau_card_init(struct drm_device *dev) + if (ret) + goto out; + engine = &dev_priv->engine; +- dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED; + spin_lock_init(&dev_priv->context_switch_lock); + + /* Parse BIOS tables / Run init tables if card not POSTed */ +- if (drm_core_check_feature(dev, DRIVER_MODESET)) { +- ret = nouveau_bios_init(dev); +- if (ret) +- goto out; +- } ++ ret = nouveau_bios_init(dev); ++ if (ret) ++ goto out; + + ret = nouveau_mem_detect(dev); + if (ret) +@@ -485,12 +474,19 @@ nouveau_card_init(struct drm_device *dev) + goto out_graph; + } + ++ if (dev_priv->card_type >= NV_50) ++ ret = nv50_display_create(dev); ++ else ++ ret = nv04_display_create(dev); ++ if (ret) ++ goto out_fifo; ++ + /* this call irq_preinstall, register irq handler and + * call irq_postinstall + */ + ret = drm_irq_install(dev); + if (ret) +- goto out_fifo; ++ goto out_display; + + ret = drm_vblank_init(dev, 0); + if (ret) +@@ -504,35 +500,21 @@ nouveau_card_init(struct drm_device *dev) + goto out_irq; + } + +- if (drm_core_check_feature(dev, DRIVER_MODESET)) { +- if (dev_priv->card_type >= NV_50) +- ret = nv50_display_create(dev); +- else +- ret = nv04_display_create(dev); +- if (ret) +- goto out_channel; +- } +- + ret = nouveau_backlight_init(dev); + if (ret) + NV_ERROR(dev, "Error %d registering backlight\n", ret); + +- dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; +- +- if (drm_core_check_feature(dev, DRIVER_MODESET)) { +- nouveau_fbcon_init(dev); +- drm_kms_helper_poll_init(dev); +- } +- ++ nouveau_fbcon_init(dev); ++ drm_kms_helper_poll_init(dev); + return 0; + +-out_channel: +- if (dev_priv->channel) { +- nouveau_channel_free(dev_priv->channel); +- dev_priv->channel = NULL; +- } + out_irq: + drm_irq_uninstall(dev); ++out_display: ++ if (dev_priv->card_type >= NV_50) ++ nv50_display_destroy(dev); ++ else ++ nv04_display_destroy(dev); + out_fifo: + if (!nouveau_noaccel) + engine->fifo.takedown(dev); +@@ -566,45 +548,37 @@ static void nouveau_card_takedown(struct drm_device *dev) + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine *engine = &dev_priv->engine; + +- NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); ++ nouveau_backlight_exit(dev); + +- if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { +- +- nouveau_backlight_exit(dev); +- +- if (dev_priv->channel) { +- nouveau_channel_free(dev_priv->channel); +- dev_priv->channel = NULL; +- } +- +- if (!nouveau_noaccel) { +- engine->fifo.takedown(dev); +- engine->graph.takedown(dev); +- } +- engine->fb.takedown(dev); +- engine->timer.takedown(dev); +- engine->mc.takedown(dev); ++ if (dev_priv->channel) { ++ nouveau_channel_free(dev_priv->channel); ++ dev_priv->channel = NULL; ++ } + +- mutex_lock(&dev->struct_mutex); +- ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); +- ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); +- mutex_unlock(&dev->struct_mutex); +- nouveau_sgdma_takedown(dev); ++ if (!nouveau_noaccel) { ++ engine->fifo.takedown(dev); ++ engine->graph.takedown(dev); ++ } ++ engine->fb.takedown(dev); ++ engine->timer.takedown(dev); ++ engine->mc.takedown(dev); + +- nouveau_gpuobj_takedown(dev); +- nouveau_mem_close(dev); +- engine->instmem.takedown(dev); ++ mutex_lock(&dev->struct_mutex); ++ ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); ++ ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); ++ mutex_unlock(&dev->struct_mutex); ++ nouveau_sgdma_takedown(dev); + +- if (drm_core_check_feature(dev, DRIVER_MODESET)) +- drm_irq_uninstall(dev); ++ nouveau_gpuobj_takedown(dev); ++ nouveau_mem_close(dev); ++ engine->instmem.takedown(dev); + +- nouveau_gpuobj_late_takedown(dev); +- nouveau_bios_takedown(dev); ++ drm_irq_uninstall(dev); + +- vga_client_register(dev->pdev, NULL, NULL, NULL); ++ nouveau_gpuobj_late_takedown(dev); ++ nouveau_bios_takedown(dev); + +- dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN; +- } ++ vga_client_register(dev->pdev, NULL, NULL, NULL); + } + + /* here a client dies, release the stuff that was allocated for its +@@ -691,6 +665,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + struct drm_nouveau_private *dev_priv; + uint32_t reg0; + resource_size_t mmio_start_offs; ++ int ret; + + dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); + if (!dev_priv) +@@ -699,7 +674,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + dev_priv->dev = dev; + + dev_priv->flags = flags & NOUVEAU_FLAGS; +- dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN; + + NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", + dev->pci_vendor, dev->pci_device, dev->pdev->class); +@@ -812,46 +786,28 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) + dev_priv->flags |= NV_NFORCE2; + + /* For kernel modesetting, init card now and bring up fbcon */ +- if (drm_core_check_feature(dev, DRIVER_MODESET)) { +- int ret = nouveau_card_init(dev); +- if (ret) +- return ret; +- } ++ ret = nouveau_card_init(dev); ++ if (ret) ++ return ret; + + return 0; + } + +-static void nouveau_close(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- +- /* In the case of an error dev_priv may not be allocated yet */ +- if (dev_priv) +- nouveau_card_takedown(dev); +-} +- +-/* KMS: we need mmio at load time, not when the first drm client opens. */ + void nouveau_lastclose(struct drm_device *dev) + { +- if (drm_core_check_feature(dev, DRIVER_MODESET)) +- return; +- +- nouveau_close(dev); + } + + int nouveau_unload(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + +- if (drm_core_check_feature(dev, DRIVER_MODESET)) { +- drm_kms_helper_poll_fini(dev); +- nouveau_fbcon_fini(dev); +- if (dev_priv->card_type >= NV_50) +- nv50_display_destroy(dev); +- else +- nv04_display_destroy(dev); +- nouveau_close(dev); +- } ++ drm_kms_helper_poll_fini(dev); ++ nouveau_fbcon_fini(dev); ++ if (dev_priv->card_type >= NV_50) ++ nv50_display_destroy(dev); ++ else ++ nv04_display_destroy(dev); ++ nouveau_card_takedown(dev); + + iounmap(dev_priv->mmio); + iounmap(dev_priv->ramin); +@@ -867,8 +823,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_nouveau_getparam *getparam = data; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; +- + switch (getparam->param) { + case NOUVEAU_GETPARAM_CHIPSET_ID: + getparam->value = dev_priv->chipset; +@@ -937,8 +891,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, + { + struct drm_nouveau_setparam *setparam = data; + +- NOUVEAU_CHECK_INITIALISED_WITH_RETURN; +- + switch (setparam->param) { + default: + NV_ERROR(dev, "unknown parameter %lld\n", setparam->param); +diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c +index eba687f..1c20c08 100644 +--- a/drivers/gpu/drm/nouveau/nv04_crtc.c ++++ b/drivers/gpu/drm/nouveau/nv04_crtc.c +@@ -157,6 +157,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) + { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + struct drm_device *dev = crtc->dev; ++ struct drm_connector *connector; + unsigned char seq1 = 0, crtc17 = 0; + unsigned char crtc1A; + +@@ -211,6 +212,10 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) + NVVgaSeqReset(dev, nv_crtc->index, false); + + NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A); ++ ++ /* Update connector polling modes */ ++ list_for_each_entry(connector, &dev->mode_config.connector_list, head) ++ nouveau_connector_set_polling(connector); + } + + static bool +diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c +index 1cb19e3..2d0fee5 100644 +--- a/drivers/gpu/drm/nouveau/nv04_dac.c ++++ b/drivers/gpu/drm/nouveau/nv04_dac.c +@@ -261,12 +261,11 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) + + saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); + head = (saved_routput & 0x100) >> 8; +-#if 0 +- /* if there's a spare crtc, using it will minimise flicker for the case +- * where the in-use crtc is in use by an off-chip tmds encoder */ +- if (xf86_config->crtc[head]->enabled && !xf86_config->crtc[head ^ 1]->enabled) ++ ++ /* if there's a spare crtc, using it will minimise flicker */ ++ if (!(NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX) & 0xC0)) + head ^= 1; +-#endif ++ + /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */ + routput = (saved_routput & 0xfffffece) | head << 8; + +@@ -315,9 +314,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) + { + struct drm_device *dev = encoder->dev; + struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; +- uint32_t sample = nv17_dac_sample_load(encoder); + +- if (sample & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { ++ if (nv04_dac_in_use(encoder)) ++ return connector_status_disconnected; ++ ++ if (nv17_dac_sample_load(encoder) & ++ NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { + NV_INFO(dev, "Load detected on output %c\n", + '@' + ffs(dcb->or)); + return connector_status_connected; +@@ -330,6 +332,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) + { ++ if (nv04_dac_in_use(encoder)) ++ return false; ++ + return true; + } + +@@ -428,6 +433,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) + } + } + ++/* Check if the DAC corresponding to 'encoder' is being used by ++ * someone else. */ ++bool nv04_dac_in_use(struct drm_encoder *encoder) ++{ ++ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; ++ struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; ++ ++ return nv_gf4_disp_arch(encoder->dev) && ++ (dev_priv->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index)); ++} ++ + static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) + { + struct drm_device *dev = encoder->dev; +@@ -501,11 +517,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = { + .destroy = nv04_dac_destroy, + }; + +-int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) ++int ++nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry) + { + const struct drm_encoder_helper_funcs *helper; +- struct drm_encoder *encoder; + struct nouveau_encoder *nv_encoder = NULL; ++ struct drm_device *dev = connector->dev; ++ struct drm_encoder *encoder; + + nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); + if (!nv_encoder) +@@ -527,5 +545,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) + encoder->possible_crtcs = entry->heads; + encoder->possible_clones = 0; + ++ drm_mode_connector_attach_encoder(connector, encoder); + return 0; + } +diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c +index 41634d4..3311f3a 100644 +--- a/drivers/gpu/drm/nouveau/nv04_dfp.c ++++ b/drivers/gpu/drm/nouveau/nv04_dfp.c +@@ -413,10 +413,6 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) + struct dcb_entry *dcbe = nv_encoder->dcb; + int head = nouveau_crtc(encoder->crtc)->index; + +- NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", +- drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), +- nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); +- + if (dcbe->type == OUTPUT_TMDS) + run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock); + else if (dcbe->type == OUTPUT_LVDS) +@@ -584,11 +580,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = { + .destroy = nv04_dfp_destroy, + }; + +-int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) ++int ++nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry) + { + const struct drm_encoder_helper_funcs *helper; +- struct drm_encoder *encoder; + struct nouveau_encoder *nv_encoder = NULL; ++ struct drm_encoder *encoder; + int type; + + switch (entry->type) { +@@ -613,11 +610,12 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) + nv_encoder->dcb = entry; + nv_encoder->or = ffs(entry->or) - 1; + +- drm_encoder_init(dev, encoder, &nv04_dfp_funcs, type); ++ drm_encoder_init(connector->dev, encoder, &nv04_dfp_funcs, type); + drm_encoder_helper_add(encoder, helper); + + encoder->possible_crtcs = entry->heads; + encoder->possible_clones = 0; + ++ drm_mode_connector_attach_encoder(connector, encoder); + return 0; + } +diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c +index c7898b4..c6df391 100644 +--- a/drivers/gpu/drm/nouveau/nv04_display.c ++++ b/drivers/gpu/drm/nouveau/nv04_display.c +@@ -32,8 +32,6 @@ + #include "nouveau_encoder.h" + #include "nouveau_connector.h" + +-#define MULTIPLE_ENCODERS(e) (e & (e - 1)) +- + static void + nv04_display_store_initial_head_owner(struct drm_device *dev) + { +@@ -41,7 +39,7 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) + + if (dev_priv->chipset != 0x11) { + dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44); +- goto ownerknown; ++ return; + } + + /* reading CR44 is broken on nv11, so we attempt to infer it */ +@@ -52,8 +50,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) + bool tvA = false; + bool tvB = false; + +- NVLockVgaCrtcs(dev, false); +- + slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) & + 0x80; + if (slaved_on_B) +@@ -66,8 +62,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) + tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) & + MASK(NV_CIO_CRE_LCD_LCD_SELECT)); + +- NVLockVgaCrtcs(dev, true); +- + if (slaved_on_A && !tvA) + dev_priv->crtc_owner = 0x0; + else if (slaved_on_B && !tvB) +@@ -79,14 +73,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) + else + dev_priv->crtc_owner = 0x0; + } +- +-ownerknown: +- NV_INFO(dev, "Initial CRTC_OWNER is %d\n", dev_priv->crtc_owner); +- +- /* we need to ensure the heads are not tied henceforth, or reading any +- * 8 bit reg on head B will fail +- * setting a single arbitrary head solves that */ +- NVSetOwner(dev, 0); + } + + int +@@ -94,14 +80,20 @@ nv04_display_create(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct dcb_table *dcb = &dev_priv->vbios.dcb; ++ struct drm_connector *connector, *ct; + struct drm_encoder *encoder; + struct drm_crtc *crtc; + int i, ret; + + NV_DEBUG_KMS(dev, "\n"); + +- if (nv_two_heads(dev)) ++ NVLockVgaCrtcs(dev, false); ++ ++ if (nv_two_heads(dev)) { + nv04_display_store_initial_head_owner(dev); ++ NVSetOwner(dev, 0); ++ } ++ + nouveau_hw_save_vga_fonts(dev, 1); + + drm_mode_config_init(dev); +@@ -132,19 +124,23 @@ nv04_display_create(struct drm_device *dev) + for (i = 0; i < dcb->entries; i++) { + struct dcb_entry *dcbent = &dcb->entry[i]; + ++ connector = nouveau_connector_create(dev, dcbent->connector); ++ if (IS_ERR(connector)) ++ continue; ++ + switch (dcbent->type) { + case OUTPUT_ANALOG: +- ret = nv04_dac_create(dev, dcbent); ++ ret = nv04_dac_create(connector, dcbent); + break; + case OUTPUT_LVDS: + case OUTPUT_TMDS: +- ret = nv04_dfp_create(dev, dcbent); ++ ret = nv04_dfp_create(connector, dcbent); + break; + case OUTPUT_TV: + if (dcbent->location == DCB_LOC_ON_CHIP) +- ret = nv17_tv_create(dev, dcbent); ++ ret = nv17_tv_create(connector, dcbent); + else +- ret = nv04_tv_create(dev, dcbent); ++ ret = nv04_tv_create(connector, dcbent); + break; + default: + NV_WARN(dev, "DCB type %d not known\n", dcbent->type); +@@ -155,12 +151,16 @@ nv04_display_create(struct drm_device *dev) + continue; + } + +- for (i = 0; i < dcb->connector.entries; i++) +- nouveau_connector_create(dev, &dcb->connector.entry[i]); ++ list_for_each_entry_safe(connector, ct, ++ &dev->mode_config.connector_list, head) { ++ if (!connector->encoder_ids[0]) { ++ NV_WARN(dev, "%s has no encoders, removing\n", ++ drm_get_connector_name(connector)); ++ connector->funcs->destroy(connector); ++ } ++ } + + /* Save previous state */ +- NVLockVgaCrtcs(dev, false); +- + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + crtc->funcs->save(crtc); + +@@ -176,6 +176,7 @@ nv04_display_create(struct drm_device *dev) + void + nv04_display_destroy(struct drm_device *dev) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder; + struct drm_crtc *crtc; + +@@ -191,8 +192,6 @@ nv04_display_destroy(struct drm_device *dev) + } + + /* Restore state */ +- NVLockVgaCrtcs(dev, false); +- + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct drm_encoder_helper_funcs *func = encoder->helper_private; + +@@ -205,12 +204,15 @@ nv04_display_destroy(struct drm_device *dev) + drm_mode_config_cleanup(dev); + + nouveau_hw_save_vga_fonts(dev, 0); ++ ++ if (nv_two_heads(dev)) ++ NVSetOwner(dev, dev_priv->crtc_owner); ++ NVLockVgaCrtcs(dev, true); + } + + void + nv04_display_restore(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder; + struct drm_crtc *crtc; + +@@ -232,13 +234,5 @@ nv04_display_restore(struct drm_device *dev) + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + crtc->funcs->restore(crtc); +- +- if (nv_two_heads(dev)) { +- NV_INFO(dev, "Restoring CRTC_OWNER to %d.\n", +- dev_priv->crtc_owner); +- NVSetOwner(dev, dev_priv->crtc_owner); +- } +- +- NVLockVgaCrtcs(dev, true); + } + +diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c +index 66fe559..06cedd9 100644 +--- a/drivers/gpu/drm/nouveau/nv04_fifo.c ++++ b/drivers/gpu/drm/nouveau/nv04_fifo.c +@@ -112,6 +112,12 @@ nv04_fifo_channel_id(struct drm_device *dev) + NV03_PFIFO_CACHE1_PUSH1_CHID_MASK; + } + ++#ifdef __BIG_ENDIAN ++#define DMA_FETCH_ENDIANNESS NV_PFIFO_CACHE1_BIG_ENDIAN ++#else ++#define DMA_FETCH_ENDIANNESS 0 ++#endif ++ + int + nv04_fifo_create_context(struct nouveau_channel *chan) + { +@@ -131,18 +137,13 @@ nv04_fifo_create_context(struct nouveau_channel *chan) + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + + /* Setup initial state */ +- dev_priv->engine.instmem.prepare_access(dev, true); + RAMFC_WR(DMA_PUT, chan->pushbuf_base); + RAMFC_WR(DMA_GET, chan->pushbuf_base); + RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4); + RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | +-#ifdef __BIG_ENDIAN +- NV_PFIFO_CACHE1_BIG_ENDIAN | +-#endif +- 0)); +- dev_priv->engine.instmem.finish_access(dev); ++ DMA_FETCH_ENDIANNESS)); + + /* enable the fifo dma operation */ + nv_wr32(dev, NV04_PFIFO_MODE, +@@ -169,8 +170,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid) + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t fc = NV04_RAMFC(chid), tmp; + +- dev_priv->engine.instmem.prepare_access(dev, false); +- + nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0)); + nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4)); + tmp = nv_ri32(dev, fc + 8); +@@ -181,8 +180,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid) + nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20)); + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24)); + +- dev_priv->engine.instmem.finish_access(dev); +- + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); + } +@@ -223,7 +220,6 @@ nv04_fifo_unload_context(struct drm_device *dev) + return -EINVAL; + } + +- dev_priv->engine.instmem.prepare_access(dev, true); + RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); + RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); + tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16; +@@ -233,7 +229,6 @@ nv04_fifo_unload_context(struct drm_device *dev) + RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH)); + RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE)); + RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1)); +- dev_priv->engine.instmem.finish_access(dev); + + nv04_fifo_do_load_context(dev, pfifo->channels - 1); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1); +@@ -297,6 +292,7 @@ nv04_fifo_init(struct drm_device *dev) + + nv04_fifo_init_intr(dev); + pfifo->enable(dev); ++ pfifo->reassign(dev, true); + + for (i = 0; i < dev_priv->engine.fifo.channels; i++) { + if (dev_priv->fifos[i]) { +diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c +index 618355e..c897342 100644 +--- a/drivers/gpu/drm/nouveau/nv04_graph.c ++++ b/drivers/gpu/drm/nouveau/nv04_graph.c +@@ -342,7 +342,7 @@ static uint32_t nv04_graph_ctx_regs[] = { + }; + + struct graph_state { +- int nv04[ARRAY_SIZE(nv04_graph_ctx_regs)]; ++ uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)]; + }; + + struct nouveau_channel * +@@ -527,8 +527,7 @@ static int + nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass, + int mthd, uint32_t data) + { +- chan->fence.last_sequence_irq = data; +- nouveau_fence_handler(chan->dev, chan->id); ++ atomic_set(&chan->fence.last_sequence_irq, data); + return 0; + } + +diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c +index a3b9563..4408232 100644 +--- a/drivers/gpu/drm/nouveau/nv04_instmem.c ++++ b/drivers/gpu/drm/nouveau/nv04_instmem.c +@@ -49,10 +49,8 @@ nv04_instmem_determine_amount(struct drm_device *dev) + NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10); + + /* Clear all of it, except the BIOS image that's in the first 64KiB */ +- dev_priv->engine.instmem.prepare_access(dev, true); + for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4) + nv_wi32(dev, i, 0x00000000); +- dev_priv->engine.instmem.finish_access(dev); + } + + static void +@@ -106,7 +104,7 @@ int nv04_instmem_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t offset; +- int ret = 0; ++ int ret; + + nv04_instmem_determine_amount(dev); + nv04_instmem_configure_fixed_tables(dev); +@@ -129,14 +127,14 @@ int nv04_instmem_init(struct drm_device *dev) + offset = 0x40000; + } + +- ret = nouveau_mem_init_heap(&dev_priv->ramin_heap, +- offset, dev_priv->ramin_rsvd_vram - offset); ++ ret = drm_mm_init(&dev_priv->ramin_heap, offset, ++ dev_priv->ramin_rsvd_vram - offset); + if (ret) { +- dev_priv->ramin_heap = NULL; +- NV_ERROR(dev, "Failed to init RAMIN heap\n"); ++ NV_ERROR(dev, "Failed to init RAMIN heap: %d\n", ret); ++ return ret; + } + +- return ret; ++ return 0; + } + + void +@@ -186,12 +184,7 @@ nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + } + + void +-nv04_instmem_prepare_access(struct drm_device *dev, bool write) +-{ +-} +- +-void +-nv04_instmem_finish_access(struct drm_device *dev) ++nv04_instmem_flush(struct drm_device *dev) + { + } + +diff --git a/drivers/gpu/drm/nouveau/nv04_mc.c b/drivers/gpu/drm/nouveau/nv04_mc.c +index 617ed1e..2af43a1 100644 +--- a/drivers/gpu/drm/nouveau/nv04_mc.c ++++ b/drivers/gpu/drm/nouveau/nv04_mc.c +@@ -11,6 +11,10 @@ nv04_mc_init(struct drm_device *dev) + */ + + nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF); ++ ++ /* Disable PROM access. */ ++ nv_wr32(dev, NV_PBUS_PCI_NV_20, NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED); ++ + return 0; + } + +diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c +index c4e3404..94e299c 100644 +--- a/drivers/gpu/drm/nouveau/nv04_tv.c ++++ b/drivers/gpu/drm/nouveau/nv04_tv.c +@@ -34,69 +34,26 @@ + + #include "i2c/ch7006.h" + +-static struct { +- struct i2c_board_info board_info; +- struct drm_encoder_funcs funcs; +- struct drm_encoder_helper_funcs hfuncs; +- void *params; +- +-} nv04_tv_encoder_info[] = { ++static struct i2c_board_info nv04_tv_encoder_info[] = { + { +- .board_info = { I2C_BOARD_INFO("ch7006", 0x75) }, +- .params = &(struct ch7006_encoder_params) { ++ I2C_BOARD_INFO("ch7006", 0x75), ++ .platform_data = &(struct ch7006_encoder_params) { + CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER, + 0, 0, 0, + CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED, + CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC +- }, ++ } + }, ++ { } + }; + +-static bool probe_i2c_addr(struct i2c_adapter *adapter, int addr) +-{ +- struct i2c_msg msg = { +- .addr = addr, +- .len = 0, +- }; +- +- return i2c_transfer(adapter, &msg, 1) == 1; +-} +- + int nv04_tv_identify(struct drm_device *dev, int i2c_index) + { +- struct nouveau_i2c_chan *i2c; +- bool was_locked; +- int i, ret; +- +- NV_TRACE(dev, "Probing TV encoders on I2C bus: %d\n", i2c_index); +- +- i2c = nouveau_i2c_find(dev, i2c_index); +- if (!i2c) +- return -ENODEV; +- +- was_locked = NVLockVgaCrtcs(dev, false); +- +- for (i = 0; i < ARRAY_SIZE(nv04_tv_encoder_info); i++) { +- if (probe_i2c_addr(&i2c->adapter, +- nv04_tv_encoder_info[i].board_info.addr)) { +- ret = i; +- break; +- } +- } +- +- if (i < ARRAY_SIZE(nv04_tv_encoder_info)) { +- NV_TRACE(dev, "Detected TV encoder: %s\n", +- nv04_tv_encoder_info[i].board_info.type); +- +- } else { +- NV_TRACE(dev, "No TV encoders found.\n"); +- i = -ENODEV; +- } +- +- NVLockVgaCrtcs(dev, was_locked); +- return i; ++ return nouveau_i2c_identify(dev, "TV encoder", ++ nv04_tv_encoder_info, i2c_index); + } + ++ + #define PLLSEL_TV_CRTC1_MASK \ + (NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \ + | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1) +@@ -214,30 +171,32 @@ static void nv04_tv_commit(struct drm_encoder *encoder) + + static void nv04_tv_destroy(struct drm_encoder *encoder) + { +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- + to_encoder_slave(encoder)->slave_funcs->destroy(encoder); + + drm_encoder_cleanup(encoder); + +- kfree(nv_encoder); ++ kfree(encoder->helper_private); ++ kfree(nouveau_encoder(encoder)); + } + +-int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) ++static const struct drm_encoder_funcs nv04_tv_funcs = { ++ .destroy = nv04_tv_destroy, ++}; ++ ++int ++nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) + { + struct nouveau_encoder *nv_encoder; + struct drm_encoder *encoder; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct i2c_adapter *adap; +- struct drm_encoder_funcs *funcs = NULL; +- struct drm_encoder_helper_funcs *hfuncs = NULL; +- struct drm_encoder_slave_funcs *sfuncs = NULL; +- int i2c_index = entry->i2c_index; ++ struct drm_device *dev = connector->dev; ++ struct drm_encoder_helper_funcs *hfuncs; ++ struct drm_encoder_slave_funcs *sfuncs; ++ struct nouveau_i2c_chan *i2c = ++ nouveau_i2c_find(dev, entry->i2c_index); + int type, ret; +- bool was_locked; + + /* Ensure that we can talk to this encoder */ +- type = nv04_tv_identify(dev, i2c_index); ++ type = nv04_tv_identify(dev, entry->i2c_index); + if (type < 0) + return type; + +@@ -246,41 +205,32 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) + if (!nv_encoder) + return -ENOMEM; + ++ hfuncs = kzalloc(sizeof(*hfuncs), GFP_KERNEL); ++ if (!hfuncs) { ++ ret = -ENOMEM; ++ goto fail_free; ++ } ++ + /* Initialize the common members */ + encoder = to_drm_encoder(nv_encoder); + +- funcs = &nv04_tv_encoder_info[type].funcs; +- hfuncs = &nv04_tv_encoder_info[type].hfuncs; +- +- drm_encoder_init(dev, encoder, funcs, DRM_MODE_ENCODER_TVDAC); ++ drm_encoder_init(dev, encoder, &nv04_tv_funcs, DRM_MODE_ENCODER_TVDAC); + drm_encoder_helper_add(encoder, hfuncs); + + encoder->possible_crtcs = entry->heads; + encoder->possible_clones = 0; +- + nv_encoder->dcb = entry; + nv_encoder->or = ffs(entry->or) - 1; + + /* Run the slave-specific initialization */ +- adap = &dev_priv->vbios.dcb.i2c[i2c_index].chan->adapter; +- +- was_locked = NVLockVgaCrtcs(dev, false); +- +- ret = drm_i2c_encoder_init(encoder->dev, to_encoder_slave(encoder), adap, +- &nv04_tv_encoder_info[type].board_info); +- +- NVLockVgaCrtcs(dev, was_locked); +- ++ ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), ++ &i2c->adapter, &nv04_tv_encoder_info[type]); + if (ret < 0) +- goto fail; ++ goto fail_cleanup; + + /* Fill the function pointers */ + sfuncs = to_encoder_slave(encoder)->slave_funcs; + +- *funcs = (struct drm_encoder_funcs) { +- .destroy = nv04_tv_destroy, +- }; +- + *hfuncs = (struct drm_encoder_helper_funcs) { + .dpms = nv04_tv_dpms, + .save = sfuncs->save, +@@ -292,14 +242,17 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) + .detect = sfuncs->detect, + }; + +- /* Set the slave encoder configuration */ +- sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params); ++ /* Attach it to the specified connector. */ ++ sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data); ++ sfuncs->create_resources(encoder, connector); ++ drm_mode_connector_attach_encoder(connector, encoder); + + return 0; + +-fail: ++fail_cleanup: + drm_encoder_cleanup(encoder); +- ++ kfree(hfuncs); ++fail_free: + kfree(nv_encoder); + return ret; + } +diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c +index 7aeabf2..7a4069c 100644 +--- a/drivers/gpu/drm/nouveau/nv10_fifo.c ++++ b/drivers/gpu/drm/nouveau/nv10_fifo.c +@@ -55,7 +55,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan) + /* Fill entries that are seen filled in dumps of nvidia driver just + * after channel's is put into DMA mode + */ +- dev_priv->engine.instmem.prepare_access(dev, true); + nv_wi32(dev, fc + 0, chan->pushbuf_base); + nv_wi32(dev, fc + 4, chan->pushbuf_base); + nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4); +@@ -66,7 +65,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan) + NV_PFIFO_CACHE1_BIG_ENDIAN | + #endif + 0); +- dev_priv->engine.instmem.finish_access(dev); + + /* enable the fifo dma operation */ + nv_wr32(dev, NV04_PFIFO_MODE, +@@ -91,8 +89,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid) + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t fc = NV10_RAMFC(chid), tmp; + +- dev_priv->engine.instmem.prepare_access(dev, false); +- + nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0)); + nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4)); + nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8)); +@@ -117,8 +113,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid) + nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 48)); + + out: +- dev_priv->engine.instmem.finish_access(dev); +- + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); + } +@@ -155,8 +149,6 @@ nv10_fifo_unload_context(struct drm_device *dev) + return 0; + fc = NV10_RAMFC(chid); + +- dev_priv->engine.instmem.prepare_access(dev, true); +- + nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); + nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); + nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT)); +@@ -179,8 +171,6 @@ nv10_fifo_unload_context(struct drm_device *dev) + nv_wi32(dev, fc + 48, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); + + out: +- dev_priv->engine.instmem.finish_access(dev); +- + nv10_fifo_do_load_context(dev, pfifo->channels - 1); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1); + return 0; +diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c +index 74c8803..bb3a284 100644 +--- a/drivers/gpu/drm/nouveau/nv17_tv.c ++++ b/drivers/gpu/drm/nouveau/nv17_tv.c +@@ -116,6 +116,21 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) + return sample; + } + ++static bool ++get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask) ++{ ++ /* Zotac FX5200 */ ++ if (dev->pdev->device == 0x0322 && ++ dev->pdev->subsystem_vendor == 0x19da && ++ (dev->pdev->subsystem_device == 0x1035 || ++ dev->pdev->subsystem_device == 0x2035)) { ++ *pin_mask = 0xc; ++ return false; ++ } ++ ++ return true; ++} ++ + static enum drm_connector_status + nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) + { +@@ -124,12 +139,20 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) + struct drm_mode_config *conf = &dev->mode_config; + struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); + struct dcb_entry *dcb = tv_enc->base.dcb; ++ bool reliable = get_tv_detect_quirks(dev, &tv_enc->pin_mask); + +- if (dev_priv->chipset == 0x42 || +- dev_priv->chipset == 0x43) +- tv_enc->pin_mask = nv42_tv_sample_load(encoder) >> 28 & 0xe; +- else +- tv_enc->pin_mask = nv17_dac_sample_load(encoder) >> 28 & 0xe; ++ if (nv04_dac_in_use(encoder)) ++ return connector_status_disconnected; ++ ++ if (reliable) { ++ if (dev_priv->chipset == 0x42 || ++ dev_priv->chipset == 0x43) ++ tv_enc->pin_mask = ++ nv42_tv_sample_load(encoder) >> 28 & 0xe; ++ else ++ tv_enc->pin_mask = ++ nv17_dac_sample_load(encoder) >> 28 & 0xe; ++ } + + switch (tv_enc->pin_mask) { + case 0x2: +@@ -154,7 +177,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) + conf->tv_subconnector_property, + tv_enc->subconnector); + +- if (tv_enc->subconnector) { ++ if (!reliable) { ++ return connector_status_unknown; ++ } else if (tv_enc->subconnector) { + NV_INFO(dev, "Load detected on output %c\n", + '@' + ffs(dcb->or)); + return connector_status_connected; +@@ -296,6 +321,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, + { + struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); + ++ if (nv04_dac_in_use(encoder)) ++ return false; ++ + if (tv_norm->kind == CTV_ENC_MODE) + adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock; + else +@@ -744,8 +772,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { + .destroy = nv17_tv_destroy, + }; + +-int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) ++int ++nv17_tv_create(struct drm_connector *connector, struct dcb_entry *entry) + { ++ struct drm_device *dev = connector->dev; + struct drm_encoder *encoder; + struct nv17_tv_encoder *tv_enc = NULL; + +@@ -774,5 +804,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) + encoder->possible_crtcs = entry->heads; + encoder->possible_clones = 0; + ++ nv17_tv_create_resources(encoder, connector); ++ drm_mode_connector_attach_encoder(connector, encoder); + return 0; + } +diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c +index d6fc0a8..191c15c 100644 +--- a/drivers/gpu/drm/nouveau/nv20_graph.c ++++ b/drivers/gpu/drm/nouveau/nv20_graph.c +@@ -370,68 +370,54 @@ nv20_graph_create_context(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *); +- unsigned int ctx_size; + unsigned int idoffs = 0x28/4; + int ret; + + switch (dev_priv->chipset) { + case 0x20: +- ctx_size = NV20_GRCTX_SIZE; + ctx_init = nv20_graph_context_init; + idoffs = 0; + break; + case 0x25: + case 0x28: +- ctx_size = NV25_GRCTX_SIZE; + ctx_init = nv25_graph_context_init; + break; + case 0x2a: +- ctx_size = NV2A_GRCTX_SIZE; + ctx_init = nv2a_graph_context_init; + idoffs = 0; + break; + case 0x30: + case 0x31: +- ctx_size = NV30_31_GRCTX_SIZE; + ctx_init = nv30_31_graph_context_init; + break; + case 0x34: +- ctx_size = NV34_GRCTX_SIZE; + ctx_init = nv34_graph_context_init; + break; + case 0x35: + case 0x36: +- ctx_size = NV35_36_GRCTX_SIZE; + ctx_init = nv35_36_graph_context_init; + break; + default: +- ctx_size = 0; +- ctx_init = nv35_36_graph_context_init; +- NV_ERROR(dev, "Please contact the devs if you want your NV%x" +- " card to work\n", dev_priv->chipset); +- return -ENOSYS; +- break; ++ BUG_ON(1); + } + +- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16, +- NVOBJ_FLAG_ZERO_ALLOC, +- &chan->ramin_grctx); ++ ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size, ++ 16, NVOBJ_FLAG_ZERO_ALLOC, ++ &chan->ramin_grctx); + if (ret) + return ret; + + /* Initialise default context values */ +- dev_priv->engine.instmem.prepare_access(dev, true); + ctx_init(dev, chan->ramin_grctx->gpuobj); + + /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */ + nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs, + (chan->id << 24) | 0x1); /* CTX_USER */ + +- nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, +- chan->ramin_grctx->instance >> 4); +- +- dev_priv->engine.instmem.finish_access(dev); ++ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, ++ chan->ramin_grctx->instance >> 4); + return 0; + } + +@@ -440,13 +426,12 @@ nv20_graph_destroy_context(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + + if (chan->ramin_grctx) + nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); + +- dev_priv->engine.instmem.prepare_access(dev, true); +- nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0); +- dev_priv->engine.instmem.finish_access(dev); ++ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0); + } + + int +@@ -538,29 +523,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, + int + nv20_graph_init(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = +- (struct drm_nouveau_private *)dev->dev_private; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + uint32_t tmp, vramsz; + int ret, i; + ++ switch (dev_priv->chipset) { ++ case 0x20: ++ pgraph->grctx_size = NV20_GRCTX_SIZE; ++ break; ++ case 0x25: ++ case 0x28: ++ pgraph->grctx_size = NV25_GRCTX_SIZE; ++ break; ++ case 0x2a: ++ pgraph->grctx_size = NV2A_GRCTX_SIZE; ++ break; ++ default: ++ NV_ERROR(dev, "unknown chipset, disabling acceleration\n"); ++ pgraph->accel_blocked = true; ++ return 0; ++ } ++ + nv_wr32(dev, NV03_PMC_ENABLE, + nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); + nv_wr32(dev, NV03_PMC_ENABLE, + nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); + +- if (!dev_priv->ctx_table) { ++ if (!pgraph->ctx_table) { + /* Create Context Pointer Table */ +- dev_priv->ctx_table_size = 32 * 4; +- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, +- dev_priv->ctx_table_size, 16, ++ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, +- &dev_priv->ctx_table); ++ &pgraph->ctx_table); + if (ret) + return ret; + } + + nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, +- dev_priv->ctx_table->instance >> 4); ++ pgraph->ctx_table->instance >> 4); + + nv20_graph_rdi(dev); + +@@ -644,34 +644,52 @@ void + nv20_graph_takedown(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + +- nouveau_gpuobj_ref_del(dev, &dev_priv->ctx_table); ++ nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table); + } + + int + nv30_graph_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + int ret, i; + ++ switch (dev_priv->chipset) { ++ case 0x30: ++ case 0x31: ++ pgraph->grctx_size = NV30_31_GRCTX_SIZE; ++ break; ++ case 0x34: ++ pgraph->grctx_size = NV34_GRCTX_SIZE; ++ break; ++ case 0x35: ++ case 0x36: ++ pgraph->grctx_size = NV35_36_GRCTX_SIZE; ++ break; ++ default: ++ NV_ERROR(dev, "unknown chipset, disabling acceleration\n"); ++ pgraph->accel_blocked = true; ++ return 0; ++ } ++ + nv_wr32(dev, NV03_PMC_ENABLE, + nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); + nv_wr32(dev, NV03_PMC_ENABLE, + nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); + +- if (!dev_priv->ctx_table) { ++ if (!pgraph->ctx_table) { + /* Create Context Pointer Table */ +- dev_priv->ctx_table_size = 32 * 4; +- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, +- dev_priv->ctx_table_size, 16, ++ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, +- &dev_priv->ctx_table); ++ &pgraph->ctx_table); + if (ret) + return ret; + } + + nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, +- dev_priv->ctx_table->instance >> 4); ++ pgraph->ctx_table->instance >> 4); + + nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); +diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c +index 500ccfd..2b67f18 100644 +--- a/drivers/gpu/drm/nouveau/nv40_fifo.c ++++ b/drivers/gpu/drm/nouveau/nv40_fifo.c +@@ -48,7 +48,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan) + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + +- dev_priv->engine.instmem.prepare_access(dev, true); + nv_wi32(dev, fc + 0, chan->pushbuf_base); + nv_wi32(dev, fc + 4, chan->pushbuf_base); + nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4); +@@ -61,7 +60,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan) + 0x30000000 /* no idea.. */); + nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4); + nv_wi32(dev, fc + 60, 0x0001FFFF); +- dev_priv->engine.instmem.finish_access(dev); + + /* enable the fifo dma operation */ + nv_wr32(dev, NV04_PFIFO_MODE, +@@ -89,8 +87,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid) + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t fc = NV40_RAMFC(chid), tmp, tmp2; + +- dev_priv->engine.instmem.prepare_access(dev, false); +- + nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0)); + nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4)); + nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8)); +@@ -127,8 +123,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid) + nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76)); + nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80)); + +- dev_priv->engine.instmem.finish_access(dev); +- + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); + } +@@ -166,7 +160,6 @@ nv40_fifo_unload_context(struct drm_device *dev) + return 0; + fc = NV40_RAMFC(chid); + +- dev_priv->engine.instmem.prepare_access(dev, true); + nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); + nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); + nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT)); +@@ -200,7 +193,6 @@ nv40_fifo_unload_context(struct drm_device *dev) + tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16); + nv_wi32(dev, fc + 72, tmp); + #endif +- dev_priv->engine.instmem.finish_access(dev); + + nv40_fifo_do_load_context(dev, pfifo->channels - 1); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, +diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c +index 704a25d..ef550ce 100644 +--- a/drivers/gpu/drm/nouveau/nv40_graph.c ++++ b/drivers/gpu/drm/nouveau/nv40_graph.c +@@ -58,6 +58,7 @@ nv40_graph_create_context(struct nouveau_channel *chan) + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; ++ struct nouveau_grctx ctx = {}; + int ret; + + ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size, +@@ -67,20 +68,13 @@ nv40_graph_create_context(struct nouveau_channel *chan) + return ret; + + /* Initialise default context values */ +- dev_priv->engine.instmem.prepare_access(dev, true); +- if (!pgraph->ctxprog) { +- struct nouveau_grctx ctx = {}; +- +- ctx.dev = chan->dev; +- ctx.mode = NOUVEAU_GRCTX_VALS; +- ctx.data = chan->ramin_grctx->gpuobj; +- nv40_grctx_init(&ctx); +- } else { +- nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj); +- } ++ ctx.dev = chan->dev; ++ ctx.mode = NOUVEAU_GRCTX_VALS; ++ ctx.data = chan->ramin_grctx->gpuobj; ++ nv40_grctx_init(&ctx); ++ + nv_wo32(dev, chan->ramin_grctx->gpuobj, 0, + chan->ramin_grctx->gpuobj->im_pramin->start); +- dev_priv->engine.instmem.finish_access(dev); + return 0; + } + +@@ -238,7 +232,8 @@ nv40_graph_init(struct drm_device *dev) + struct drm_nouveau_private *dev_priv = + (struct drm_nouveau_private *)dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; +- uint32_t vramsz; ++ struct nouveau_grctx ctx = {}; ++ uint32_t vramsz, *cp; + int i, j; + + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & +@@ -246,32 +241,22 @@ nv40_graph_init(struct drm_device *dev) + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | + NV_PMC_ENABLE_PGRAPH); + +- if (nouveau_ctxfw) { +- nouveau_grctx_prog_load(dev); +- dev_priv->engine.graph.grctx_size = 175 * 1024; +- } ++ cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL); ++ if (!cp) ++ return -ENOMEM; + +- if (!dev_priv->engine.graph.ctxprog) { +- struct nouveau_grctx ctx = {}; +- uint32_t *cp; ++ ctx.dev = dev; ++ ctx.mode = NOUVEAU_GRCTX_PROG; ++ ctx.data = cp; ++ ctx.ctxprog_max = 256; ++ nv40_grctx_init(&ctx); ++ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; + +- cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL); +- if (!cp) +- return -ENOMEM; ++ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); ++ for (i = 0; i < ctx.ctxprog_len; i++) ++ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]); + +- ctx.dev = dev; +- ctx.mode = NOUVEAU_GRCTX_PROG; +- ctx.data = cp; +- ctx.ctxprog_max = 256; +- nv40_grctx_init(&ctx); +- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; +- +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); +- for (i = 0; i < ctx.ctxprog_len; i++) +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]); +- +- kfree(cp); +- } ++ kfree(cp); + + /* No context present currently */ + nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); +@@ -407,7 +392,6 @@ nv40_graph_init(struct drm_device *dev) + + void nv40_graph_takedown(struct drm_device *dev) + { +- nouveau_grctx_fini(dev); + } + + struct nouveau_pgraph_object_class nv40_graph_grclass[] = { +diff --git a/drivers/gpu/drm/nouveau/nv40_mc.c b/drivers/gpu/drm/nouveau/nv40_mc.c +index 2a3495e..e4e72c1 100644 +--- a/drivers/gpu/drm/nouveau/nv40_mc.c ++++ b/drivers/gpu/drm/nouveau/nv40_mc.c +@@ -19,7 +19,7 @@ nv40_mc_init(struct drm_device *dev) + case 0x46: /* G72 */ + case 0x4e: + case 0x4c: /* C51_G7X */ +- tmp = nv_rd32(dev, NV40_PFB_020C); ++ tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA); + nv_wr32(dev, NV40_PMC_1700, tmp); + nv_wr32(dev, NV40_PMC_1704, 0); + nv_wr32(dev, NV40_PMC_1708, 0); +diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c +index b4e4a3b..5d11ea1 100644 +--- a/drivers/gpu/drm/nouveau/nv50_crtc.c ++++ b/drivers/gpu/drm/nouveau/nv50_crtc.c +@@ -440,47 +440,15 @@ nv50_crtc_prepare(struct drm_crtc *crtc) + { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + struct drm_device *dev = crtc->dev; +- struct drm_encoder *encoder; +- uint32_t dac = 0, sor = 0; + + NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); + +- /* Disconnect all unused encoders. */ +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- +- if (!drm_helper_encoder_in_use(encoder)) +- continue; +- +- if (nv_encoder->dcb->type == OUTPUT_ANALOG || +- nv_encoder->dcb->type == OUTPUT_TV) +- dac |= (1 << nv_encoder->or); +- else +- sor |= (1 << nv_encoder->or); +- } +- +- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- +- if (nv_encoder->dcb->type == OUTPUT_ANALOG || +- nv_encoder->dcb->type == OUTPUT_TV) { +- if (dac & (1 << nv_encoder->or)) +- continue; +- } else { +- if (sor & (1 << nv_encoder->or)) +- continue; +- } +- +- nv_encoder->disconnect(nv_encoder); +- } +- + nv50_crtc_blank(nv_crtc, true); + } + + static void + nv50_crtc_commit(struct drm_crtc *crtc) + { +- struct drm_crtc *crtc2; + struct drm_device *dev = crtc->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *evo = dev_priv->evo; +@@ -491,20 +459,14 @@ nv50_crtc_commit(struct drm_crtc *crtc) + + nv50_crtc_blank(nv_crtc, false); + +- /* Explicitly blank all unused crtc's. */ +- list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) { +- if (!drm_helper_crtc_in_use(crtc2)) +- nv50_crtc_blank(nouveau_crtc(crtc2), true); +- } +- + ret = RING_SPACE(evo, 2); + if (ret) { + NV_ERROR(dev, "no space while committing crtc\n"); + return; + } + BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); +- OUT_RING(evo, 0); +- FIRE_RING(evo); ++ OUT_RING (evo, 0); ++ FIRE_RING (evo); + } + + static bool +diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c +index 1fd9537..1bc0859 100644 +--- a/drivers/gpu/drm/nouveau/nv50_dac.c ++++ b/drivers/gpu/drm/nouveau/nv50_dac.c +@@ -37,22 +37,31 @@ + #include "nv50_display.h" + + static void +-nv50_dac_disconnect(struct nouveau_encoder *nv_encoder) ++nv50_dac_disconnect(struct drm_encoder *encoder) + { +- struct drm_device *dev = to_drm_encoder(nv_encoder)->dev; ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *evo = dev_priv->evo; + int ret; + ++ if (!nv_encoder->crtc) ++ return; ++ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true); ++ + NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or); + +- ret = RING_SPACE(evo, 2); ++ ret = RING_SPACE(evo, 4); + if (ret) { + NV_ERROR(dev, "no space while disconnecting DAC\n"); + return; + } + BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1); +- OUT_RING(evo, 0); ++ OUT_RING (evo, 0); ++ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); ++ OUT_RING (evo, 0); ++ ++ nv_encoder->crtc = NULL; + } + + static enum drm_connector_status +@@ -213,7 +222,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + uint32_t mode_ctl = 0, mode_ctl2 = 0; + int ret; + +- NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or); ++ NV_DEBUG_KMS(dev, "or %d type %d crtc %d\n", ++ nv_encoder->or, nv_encoder->dcb->type, crtc->index); + + nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON); + +@@ -243,6 +253,14 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2); + OUT_RING(evo, mode_ctl); + OUT_RING(evo, mode_ctl2); ++ ++ nv_encoder->crtc = encoder->crtc; ++} ++ ++static struct drm_crtc * ++nv50_dac_crtc_get(struct drm_encoder *encoder) ++{ ++ return nouveau_encoder(encoder)->crtc; + } + + static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = { +@@ -253,7 +271,9 @@ static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = { + .prepare = nv50_dac_prepare, + .commit = nv50_dac_commit, + .mode_set = nv50_dac_mode_set, +- .detect = nv50_dac_detect ++ .get_crtc = nv50_dac_crtc_get, ++ .detect = nv50_dac_detect, ++ .disable = nv50_dac_disconnect + }; + + static void +@@ -275,14 +295,11 @@ static const struct drm_encoder_funcs nv50_dac_encoder_funcs = { + }; + + int +-nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry) ++nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry) + { + struct nouveau_encoder *nv_encoder; + struct drm_encoder *encoder; + +- NV_DEBUG_KMS(dev, "\n"); +- NV_INFO(dev, "Detected a DAC output\n"); +- + nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); + if (!nv_encoder) + return -ENOMEM; +@@ -291,14 +308,14 @@ nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry) + nv_encoder->dcb = entry; + nv_encoder->or = ffs(entry->or) - 1; + +- nv_encoder->disconnect = nv50_dac_disconnect; +- +- drm_encoder_init(dev, encoder, &nv50_dac_encoder_funcs, ++ drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC); + drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs); + + encoder->possible_crtcs = entry->heads; + encoder->possible_clones = 0; ++ ++ drm_mode_connector_attach_encoder(connector, encoder); + return 0; + } + +diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c +index 580a5d1..c19ed8c 100644 +--- a/drivers/gpu/drm/nouveau/nv50_display.c ++++ b/drivers/gpu/drm/nouveau/nv50_display.c +@@ -71,14 +71,13 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, + return ret; + } + +- dev_priv->engine.instmem.prepare_access(dev, true); + nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); + nv_wo32(dev, obj, 1, limit); + nv_wo32(dev, obj, 2, offset); + nv_wo32(dev, obj, 3, 0x00000000); + nv_wo32(dev, obj, 4, 0x00000000); + nv_wo32(dev, obj, 5, 0x00010000); +- dev_priv->engine.instmem.finish_access(dev); ++ dev_priv->engine.instmem.flush(dev); + + return 0; + } +@@ -110,8 +109,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) + return ret; + } + +- ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj-> +- im_pramin->start, 32768); ++ ret = drm_mm_init(&chan->ramin_heap, ++ chan->ramin->gpuobj->im_pramin->start, 32768); + if (ret) { + NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); + nv50_evo_channel_del(pchan); +@@ -465,6 +464,7 @@ int nv50_display_create(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct dcb_table *dcb = &dev_priv->vbios.dcb; ++ struct drm_connector *connector, *ct; + int ret, i; + + NV_DEBUG_KMS(dev, "\n"); +@@ -507,14 +507,18 @@ int nv50_display_create(struct drm_device *dev) + continue; + } + ++ connector = nouveau_connector_create(dev, entry->connector); ++ if (IS_ERR(connector)) ++ continue; ++ + switch (entry->type) { + case OUTPUT_TMDS: + case OUTPUT_LVDS: + case OUTPUT_DP: +- nv50_sor_create(dev, entry); ++ nv50_sor_create(connector, entry); + break; + case OUTPUT_ANALOG: +- nv50_dac_create(dev, entry); ++ nv50_dac_create(connector, entry); + break; + default: + NV_WARN(dev, "DCB encoder %d unknown\n", entry->type); +@@ -522,11 +526,13 @@ int nv50_display_create(struct drm_device *dev) + } + } + +- for (i = 0 ; i < dcb->connector.entries; i++) { +- if (i != 0 && dcb->connector.entry[i].index2 == +- dcb->connector.entry[i - 1].index2) +- continue; +- nouveau_connector_create(dev, &dcb->connector.entry[i]); ++ list_for_each_entry_safe(connector, ct, ++ &dev->mode_config.connector_list, head) { ++ if (!connector->encoder_ids[0]) { ++ NV_WARN(dev, "%s has no encoders, removing\n", ++ drm_get_connector_name(connector)); ++ connector->funcs->destroy(connector); ++ } + } + + ret = nv50_display_init(dev); +@@ -552,131 +558,28 @@ int nv50_display_destroy(struct drm_device *dev) + return 0; + } + +-static inline uint32_t +-nv50_display_mode_ctrl(struct drm_device *dev, bool sor, int or) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- uint32_t mc; +- +- if (sor) { +- if (dev_priv->chipset < 0x90 || +- dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0) +- mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(or)); +- else +- mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(or)); +- } else { +- mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(or)); +- } +- +- return mc; +-} +- +-static int +-nv50_display_irq_head(struct drm_device *dev, int *phead, +- struct dcb_entry **pdcbent) +-{ +- 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 = 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 +- * ever, but it definitely shouldn't for us as we commit each +- * CRTC separately, and submission will be blocked by the GPU +- * until we handle each in turn. +- */ +- NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); +- head = ffs((unk30 >> 9) & 3) - 1; +- if (head < 0) +- return -EINVAL; +- +- /* This assumes CRTCs are never bound to multiple encoders, which +- * should be the case. +- */ +- for (i = 0; i < 3 && type == OUTPUT_ANY; i++) { +- uint32_t mc = nv50_display_mode_ctrl(dev, false, i); +- if (!(mc & (1 << head))) +- continue; +- +- 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; +- } +- +- for (i = 0; i < 4 && type == OUTPUT_ANY; i++) { +- uint32_t mc = nv50_display_mode_ctrl(dev, true, i); +- if (!(mc & (1 << head))) +- continue; +- +- 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; +- } +- +- or = i; +- } +- +- NV_DEBUG_KMS(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 (dcbent->type != type) +- continue; +- +- if (!(dcbent->or & (1 << or))) +- continue; +- +- *phead = head; +- *pdcbent = dcbent; +- return 0; +- } +- +- NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or); +- return 0; +-} +- +-static uint32_t +-nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent, +- int pxclk) ++static u16 ++nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb, ++ u32 mc, int pxclk) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_connector *nv_connector = NULL; + struct drm_encoder *encoder; + struct nvbios *bios = &dev_priv->vbios; +- uint32_t mc, script = 0, or; ++ u32 script = 0, or; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + +- if (nv_encoder->dcb != dcbent) ++ if (nv_encoder->dcb != dcb) + continue; + + nv_connector = nouveau_encoder_connector_get(nv_encoder); + break; + } + +- or = ffs(dcbent->or) - 1; +- mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or); +- switch (dcbent->type) { ++ or = ffs(dcb->or) - 1; ++ switch (dcb->type) { + case OUTPUT_LVDS: + script = (mc >> 8) & 0xf; + if (bios->fp_no_ddc) { +@@ -767,17 +670,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) + static void + nv50_display_unk10_handler(struct drm_device *dev) + { +- struct dcb_entry *dcbent; +- int head, ret; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 unk30 = nv_rd32(dev, 0x610030), mc; ++ int i, crtc, or, type = OUTPUT_ANY; + +- ret = nv50_display_irq_head(dev, &head, &dcbent); +- if (ret) +- goto ack; ++ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); ++ dev_priv->evo_irq.dcb = NULL; + + nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8); + +- nouveau_bios_run_display_table(dev, dcbent, 0, -1); ++ /* Determine which CRTC we're dealing with, only 1 ever will be ++ * signalled at the same time with the current nouveau code. ++ */ ++ crtc = ffs((unk30 & 0x00000060) >> 5) - 1; ++ if (crtc < 0) ++ goto ack; ++ ++ /* Nothing needs to be done for the encoder */ ++ crtc = ffs((unk30 & 0x00000180) >> 7) - 1; ++ if (crtc < 0) ++ goto ack; ++ ++ /* Find which encoder was connected to the CRTC */ ++ for (i = 0; type == OUTPUT_ANY && i < 3; i++) { ++ mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i)); ++ NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc); ++ if (!(mc & (1 << crtc))) ++ continue; ++ ++ switch ((mc & 0x00000f00) >> 8) { ++ case 0: type = OUTPUT_ANALOG; break; ++ case 1: type = OUTPUT_TV; break; ++ default: ++ NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc); ++ goto ack; ++ } ++ ++ or = i; ++ } ++ ++ for (i = 0; type == OUTPUT_ANY && i < 4; i++) { ++ if (dev_priv->chipset < 0x90 || ++ dev_priv->chipset == 0x92 || ++ dev_priv->chipset == 0xa0) ++ mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i)); ++ else ++ mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i)); + ++ NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc); ++ if (!(mc & (1 << crtc))) ++ continue; ++ ++ switch ((mc & 0x00000f00) >> 8) { ++ 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, "invalid mc, SOR-%d: 0x%08x\n", i, mc); ++ goto ack; ++ } ++ ++ or = i; ++ } ++ ++ /* There was no encoder to disable */ ++ if (type == OUTPUT_ANY) ++ goto ack; ++ ++ /* Disable the encoder */ ++ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { ++ struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; ++ ++ if (dcb->type == type && (dcb->or & (1 << or))) { ++ nouveau_bios_run_display_table(dev, dcb, 0, -1); ++ dev_priv->evo_irq.dcb = dcb; ++ goto ack; ++ } ++ } ++ ++ NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc); + ack: + nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10); + nv_wr32(dev, 0x610030, 0x80000000); +@@ -817,33 +791,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) + static void + nv50_display_unk20_handler(struct drm_device *dev) + { +- struct dcb_entry *dcbent; +- uint32_t tmp, pclk, script; +- int head, or, ret; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc; ++ struct dcb_entry *dcb; ++ int i, crtc, or, type = OUTPUT_ANY; + +- ret = nv50_display_irq_head(dev, &head, &dcbent); +- if (ret) ++ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); ++ dcb = dev_priv->evo_irq.dcb; ++ if (dcb) { ++ nouveau_bios_run_display_table(dev, dcb, 0, -2); ++ dev_priv->evo_irq.dcb = NULL; ++ } ++ ++ /* CRTC clock change requested? */ ++ crtc = ffs((unk30 & 0x00000600) >> 9) - 1; ++ if (crtc >= 0) { ++ pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)); ++ pclk &= 0x003fffff; ++ ++ nv50_crtc_set_clock(dev, crtc, pclk); ++ ++ tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc)); ++ tmp &= ~0x000000f; ++ nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp); ++ } ++ ++ /* Nothing needs to be done for the encoder */ ++ crtc = ffs((unk30 & 0x00000180) >> 7) - 1; ++ if (crtc < 0) + goto ack; +- or = ffs(dcbent->or) - 1; +- pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff; +- script = nv50_display_script_select(dev, dcbent, pclk); ++ pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff; + +- NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk); ++ /* Find which encoder is connected to the CRTC */ ++ for (i = 0; type == OUTPUT_ANY && i < 3; i++) { ++ mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i)); ++ NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc); ++ if (!(mc & (1 << crtc))) ++ continue; + +- if (dcbent->type != OUTPUT_DP) +- nouveau_bios_run_display_table(dev, dcbent, 0, -2); ++ switch ((mc & 0x00000f00) >> 8) { ++ case 0: type = OUTPUT_ANALOG; break; ++ case 1: type = OUTPUT_TV; break; ++ default: ++ NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc); ++ goto ack; ++ } + +- nv50_crtc_set_clock(dev, head, pclk); ++ or = i; ++ } + +- nouveau_bios_run_display_table(dev, dcbent, script, pclk); ++ for (i = 0; type == OUTPUT_ANY && i < 4; i++) { ++ if (dev_priv->chipset < 0x90 || ++ dev_priv->chipset == 0x92 || ++ dev_priv->chipset == 0xa0) ++ mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i)); ++ else ++ mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i)); + +- nv50_display_unk20_dp_hack(dev, dcbent); ++ NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc); ++ if (!(mc & (1 << crtc))) ++ continue; + +- tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head)); +- tmp &= ~0x000000f; +- nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp); ++ switch ((mc & 0x00000f00) >> 8) { ++ 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, "invalid mc, SOR-%d: 0x%08x\n", i, mc); ++ goto ack; ++ } ++ ++ or = i; ++ } ++ ++ if (type == OUTPUT_ANY) ++ goto ack; ++ ++ /* Enable the encoder */ ++ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { ++ dcb = &dev_priv->vbios.dcb.entry[i]; ++ if (dcb->type == type && (dcb->or & (1 << or))) ++ break; ++ } ++ ++ if (i == dev_priv->vbios.dcb.entries) { ++ NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc); ++ goto ack; ++ } ++ ++ script = nv50_display_script_select(dev, dcb, mc, pclk); ++ nouveau_bios_run_display_table(dev, dcb, script, pclk); ++ ++ nv50_display_unk20_dp_hack(dev, dcb); + +- if (dcbent->type != OUTPUT_ANALOG) { ++ if (dcb->type != OUTPUT_ANALOG) { + tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); + tmp &= ~0x00000f0f; + if (script & 0x0100) +@@ -853,24 +897,61 @@ nv50_display_unk20_handler(struct drm_device *dev) + nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0); + } + ++ dev_priv->evo_irq.dcb = dcb; ++ dev_priv->evo_irq.pclk = pclk; ++ dev_priv->evo_irq.script = script; ++ + ack: + nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20); + nv_wr32(dev, 0x610030, 0x80000000); + } + ++/* If programming a TMDS output on a SOR that can also be configured for ++ * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off. ++ * ++ * It looks like the VBIOS TMDS scripts make an attempt at this, however, ++ * the VBIOS scripts on at least one board I have only switch it off on ++ * link 0, causing a blank display if the output has previously been ++ * programmed for DisplayPort. ++ */ ++static void ++nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb) ++{ ++ int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1); ++ struct drm_encoder *encoder; ++ u32 tmp; ++ ++ if (dcb->type != OUTPUT_TMDS) ++ return; ++ ++ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ ++ if (nv_encoder->dcb->type == OUTPUT_DP && ++ nv_encoder->dcb->or & (1 << or)) { ++ tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); ++ tmp &= ~NV50_SOR_DP_CTRL_ENABLED; ++ nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp); ++ break; ++ } ++ } ++} ++ + static void + nv50_display_unk40_handler(struct drm_device *dev) + { +- struct dcb_entry *dcbent; +- int head, pclk, script, ret; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct dcb_entry *dcb = dev_priv->evo_irq.dcb; ++ u16 script = dev_priv->evo_irq.script; ++ u32 unk30 = nv_rd32(dev, 0x610030), pclk = dev_priv->evo_irq.pclk; + +- ret = nv50_display_irq_head(dev, &head, &dcbent); +- if (ret) ++ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); ++ dev_priv->evo_irq.dcb = NULL; ++ if (!dcb) + goto ack; +- pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff; +- script = nv50_display_script_select(dev, dcbent, pclk); + +- nouveau_bios_run_display_table(dev, dcbent, script, -pclk); ++ nouveau_bios_run_display_table(dev, dcb, script, -pclk); ++ nv50_display_unk40_dp_set_tmds(dev, dcb); + + ack: + nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40); +diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c +index e20c0e2..fb0281a 100644 +--- a/drivers/gpu/drm/nouveau/nv50_fifo.c ++++ b/drivers/gpu/drm/nouveau/nv50_fifo.c +@@ -28,41 +28,33 @@ + #include "drm.h" + #include "nouveau_drv.h" + +-struct nv50_fifo_priv { +- struct nouveau_gpuobj_ref *thingo[2]; +- int cur_thingo; +-}; +- +-#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) +- + static void +-nv50_fifo_init_thingo(struct drm_device *dev) ++nv50_fifo_playlist_update(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv; ++ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_gpuobj_ref *cur; + int i, nr; + + NV_DEBUG(dev, "\n"); + +- cur = priv->thingo[priv->cur_thingo]; +- priv->cur_thingo = !priv->cur_thingo; ++ cur = pfifo->playlist[pfifo->cur_playlist]; ++ pfifo->cur_playlist = !pfifo->cur_playlist; + + /* We never schedule channel 0 or 127 */ +- dev_priv->engine.instmem.prepare_access(dev, true); + for (i = 1, nr = 0; i < 127; i++) { + if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) + nv_wo32(dev, cur->gpuobj, nr++, i); + } +- dev_priv->engine.instmem.finish_access(dev); ++ dev_priv->engine.instmem.flush(dev); + + nv_wr32(dev, 0x32f4, cur->instance >> 12); + nv_wr32(dev, 0x32ec, nr); + nv_wr32(dev, 0x2500, 0x101); + } + +-static int +-nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt) ++static void ++nv50_fifo_channel_enable(struct drm_device *dev, int channel) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = dev_priv->fifos[channel]; +@@ -70,37 +62,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt) + + NV_DEBUG(dev, "ch%d\n", channel); + +- if (!chan->ramfc) +- return -EINVAL; +- +- if (IS_G80) ++ if (dev_priv->chipset == 0x50) + inst = chan->ramfc->instance >> 12; + else + inst = chan->ramfc->instance >> 8; +- nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), +- inst | NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED); + +- if (!nt) +- nv50_fifo_init_thingo(dev); +- return 0; ++ nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst | ++ NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED); + } + + static void +-nv50_fifo_channel_disable(struct drm_device *dev, int channel, bool nt) ++nv50_fifo_channel_disable(struct drm_device *dev, int channel) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t inst; + +- NV_DEBUG(dev, "ch%d, nt=%d\n", channel, nt); ++ NV_DEBUG(dev, "ch%d\n", channel); + +- if (IS_G80) ++ if (dev_priv->chipset == 0x50) + inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80; + else + inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84; + nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst); +- +- if (!nt) +- nv50_fifo_init_thingo(dev); + } + + static void +@@ -133,12 +116,12 @@ nv50_fifo_init_context_table(struct drm_device *dev) + + for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) { + if (dev_priv->fifos[i]) +- nv50_fifo_channel_enable(dev, i, true); ++ nv50_fifo_channel_enable(dev, i); + else +- nv50_fifo_channel_disable(dev, i, true); ++ nv50_fifo_channel_disable(dev, i); + } + +- nv50_fifo_init_thingo(dev); ++ nv50_fifo_playlist_update(dev); + } + + static void +@@ -162,41 +145,38 @@ nv50_fifo_init_regs(struct drm_device *dev) + nv_wr32(dev, 0x3270, 0); + + /* Enable dummy channels setup by nv50_instmem.c */ +- nv50_fifo_channel_enable(dev, 0, true); +- nv50_fifo_channel_enable(dev, 127, true); ++ nv50_fifo_channel_enable(dev, 0); ++ nv50_fifo_channel_enable(dev, 127); + } + + int + nv50_fifo_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nv50_fifo_priv *priv; ++ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + int ret; + + NV_DEBUG(dev, "\n"); + +- priv = dev_priv->engine.fifo.priv; +- if (priv) { +- priv->cur_thingo = !priv->cur_thingo; ++ if (pfifo->playlist[0]) { ++ pfifo->cur_playlist = !pfifo->cur_playlist; + goto just_reset; + } + +- priv = kzalloc(sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- dev_priv->engine.fifo.priv = priv; +- + ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000, +- NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[0]); ++ NVOBJ_FLAG_ZERO_ALLOC, ++ &pfifo->playlist[0]); + if (ret) { +- NV_ERROR(dev, "error creating thingo0: %d\n", ret); ++ NV_ERROR(dev, "error creating playlist 0: %d\n", ret); + return ret; + } + + ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000, +- NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[1]); ++ NVOBJ_FLAG_ZERO_ALLOC, ++ &pfifo->playlist[1]); + if (ret) { +- NV_ERROR(dev, "error creating thingo1: %d\n", ret); ++ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]); ++ NV_ERROR(dev, "error creating playlist 1: %d\n", ret); + return ret; + } + +@@ -216,18 +196,15 @@ void + nv50_fifo_takedown(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv; ++ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + + NV_DEBUG(dev, "\n"); + +- if (!priv) ++ if (!pfifo->playlist[0]) + return; + +- nouveau_gpuobj_ref_del(dev, &priv->thingo[0]); +- nouveau_gpuobj_ref_del(dev, &priv->thingo[1]); +- +- dev_priv->engine.fifo.priv = NULL; +- kfree(priv); ++ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]); ++ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]); + } + + int +@@ -248,7 +225,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) + + NV_DEBUG(dev, "ch%d\n", chan->id); + +- if (IS_G80) { ++ if (dev_priv->chipset == 0x50) { + uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start; + uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start; + +@@ -281,10 +258,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan) + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + +- dev_priv->engine.instmem.prepare_access(dev, true); +- + nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4); +- nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4)); ++ nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ | ++ (4 << 24) /* SEARCH_FULL */ | ++ (chan->ramht->instance >> 4)); + nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff); + nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff); + nv_wo32(dev, ramfc, 0x40/4, 0x00000000); +@@ -295,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) + chan->dma.ib_base * 4); + nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16); + +- if (!IS_G80) { ++ if (dev_priv->chipset != 0x50) { + nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id); + nv_wo32(dev, chan->ramin->gpuobj, 1, + chan->ramfc->instance >> 8); +@@ -304,16 +281,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan) + nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12); + } + +- dev_priv->engine.instmem.finish_access(dev); +- +- ret = nv50_fifo_channel_enable(dev, chan->id, false); +- if (ret) { +- NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret); +- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +- nouveau_gpuobj_ref_del(dev, &chan->ramfc); +- return ret; +- } ++ dev_priv->engine.instmem.flush(dev); + ++ nv50_fifo_channel_enable(dev, chan->id); ++ nv50_fifo_playlist_update(dev); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + return 0; + } +@@ -328,11 +299,12 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan) + + /* This will ensure the channel is seen as disabled. */ + chan->ramfc = NULL; +- nv50_fifo_channel_disable(dev, chan->id, false); ++ nv50_fifo_channel_disable(dev, chan->id); + + /* Dummy channel, also used on ch 127 */ + if (chan->id == 0) +- nv50_fifo_channel_disable(dev, 127, false); ++ nv50_fifo_channel_disable(dev, 127); ++ nv50_fifo_playlist_update(dev); + + nouveau_gpuobj_ref_del(dev, &ramfc); + nouveau_gpuobj_ref_del(dev, &chan->cache); +@@ -349,8 +321,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan) + + NV_DEBUG(dev, "ch%d\n", chan->id); + +- dev_priv->engine.instmem.prepare_access(dev, false); +- + nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4)); + nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4)); + nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4)); +@@ -396,7 +366,7 @@ nv50_fifo_load_context(struct nouveau_channel *chan) + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); + + /* guessing that all the 0x34xx regs aren't on NV50 */ +- if (!IS_G80) { ++ if (dev_priv->chipset != 0x50) { + nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4)); + nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4)); + nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4)); +@@ -404,8 +374,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan) + nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4)); + } + +- dev_priv->engine.instmem.finish_access(dev); +- + nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16)); + return 0; + } +@@ -434,8 +402,6 @@ nv50_fifo_unload_context(struct drm_device *dev) + ramfc = chan->ramfc->gpuobj; + cache = chan->cache->gpuobj; + +- dev_priv->engine.instmem.prepare_access(dev, true); +- + nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330)); + nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334)); + nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240)); +@@ -482,7 +448,7 @@ nv50_fifo_unload_context(struct drm_device *dev) + } + + /* guessing that all the 0x34xx regs aren't on NV50 */ +- if (!IS_G80) { ++ if (dev_priv->chipset != 0x50) { + nv_wo32(dev, ramfc, 0x84/4, ptr >> 1); + nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c)); + nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400)); +@@ -491,7 +457,7 @@ nv50_fifo_unload_context(struct drm_device *dev) + nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410)); + } + +- dev_priv->engine.instmem.finish_access(dev); ++ dev_priv->engine.instmem.flush(dev); + + /*XXX: probably reload ch127 (NULL) state back too */ + nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, 127); +diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c +index b203d06..1413028 100644 +--- a/drivers/gpu/drm/nouveau/nv50_graph.c ++++ b/drivers/gpu/drm/nouveau/nv50_graph.c +@@ -30,8 +30,6 @@ + + #include "nouveau_grctx.h" + +-#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) +- + static void + nv50_graph_init_reset(struct drm_device *dev) + { +@@ -103,37 +101,33 @@ static int + nv50_graph_init_ctxctl(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_grctx ctx = {}; ++ uint32_t *cp; ++ int i; + + NV_DEBUG(dev, "\n"); + +- if (nouveau_ctxfw) { +- nouveau_grctx_prog_load(dev); +- dev_priv->engine.graph.grctx_size = 0x70000; ++ cp = kmalloc(512 * 4, GFP_KERNEL); ++ if (!cp) { ++ NV_ERROR(dev, "failed to allocate ctxprog\n"); ++ dev_priv->engine.graph.accel_blocked = true; ++ return 0; + } +- if (!dev_priv->engine.graph.ctxprog) { +- struct nouveau_grctx ctx = {}; +- uint32_t *cp = kmalloc(512 * 4, GFP_KERNEL); +- int i; +- if (!cp) { +- NV_ERROR(dev, "Couldn't alloc ctxprog! Disabling acceleration.\n"); +- dev_priv->engine.graph.accel_blocked = true; +- return 0; +- } +- ctx.dev = dev; +- ctx.mode = NOUVEAU_GRCTX_PROG; +- ctx.data = cp; +- ctx.ctxprog_max = 512; +- if (!nv50_grctx_init(&ctx)) { +- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; +- +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); +- for (i = 0; i < ctx.ctxprog_len; i++) +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]); +- } else { +- dev_priv->engine.graph.accel_blocked = true; +- } +- kfree(cp); ++ ++ ctx.dev = dev; ++ ctx.mode = NOUVEAU_GRCTX_PROG; ++ ctx.data = cp; ++ ctx.ctxprog_max = 512; ++ if (!nv50_grctx_init(&ctx)) { ++ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; ++ ++ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); ++ for (i = 0; i < ctx.ctxprog_len; i++) ++ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]); ++ } else { ++ dev_priv->engine.graph.accel_blocked = true; + } ++ kfree(cp); + + nv_wr32(dev, 0x400320, 4); + nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0); +@@ -164,7 +158,6 @@ void + nv50_graph_takedown(struct drm_device *dev) + { + NV_DEBUG(dev, "\n"); +- nouveau_grctx_fini(dev); + } + + void +@@ -212,8 +205,9 @@ nv50_graph_create_context(struct nouveau_channel *chan) + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; +- struct nouveau_gpuobj *ctx; ++ struct nouveau_gpuobj *obj; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; ++ struct nouveau_grctx ctx = {}; + int hdr, ret; + + NV_DEBUG(dev, "ch%d\n", chan->id); +@@ -223,10 +217,9 @@ nv50_graph_create_context(struct nouveau_channel *chan) + NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); + if (ret) + return ret; +- ctx = chan->ramin_grctx->gpuobj; ++ obj = chan->ramin_grctx->gpuobj; + +- hdr = IS_G80 ? 0x200 : 0x20; +- dev_priv->engine.instmem.prepare_access(dev, true); ++ hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; + nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002); + nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance + + pgraph->grctx_size - 1); +@@ -234,21 +227,15 @@ nv50_graph_create_context(struct nouveau_channel *chan) + nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0); + nv_wo32(dev, ramin, (hdr + 0x10)/4, 0); + nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000); +- dev_priv->engine.instmem.finish_access(dev); +- +- dev_priv->engine.instmem.prepare_access(dev, true); +- if (!pgraph->ctxprog) { +- struct nouveau_grctx ctx = {}; +- ctx.dev = chan->dev; +- ctx.mode = NOUVEAU_GRCTX_VALS; +- ctx.data = chan->ramin_grctx->gpuobj; +- nv50_grctx_init(&ctx); +- } else { +- nouveau_grctx_vals_load(dev, ctx); +- } +- nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12); +- dev_priv->engine.instmem.finish_access(dev); + ++ ctx.dev = chan->dev; ++ ctx.mode = NOUVEAU_GRCTX_VALS; ++ ctx.data = obj; ++ nv50_grctx_init(&ctx); ++ ++ nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12); ++ ++ dev_priv->engine.instmem.flush(dev); + return 0; + } + +@@ -257,17 +244,16 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- int i, hdr = IS_G80 ? 0x200 : 0x20; ++ int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; + + NV_DEBUG(dev, "ch%d\n", chan->id); + + if (!chan->ramin || !chan->ramin->gpuobj) + return; + +- dev_priv->engine.instmem.prepare_access(dev, true); + for (i = hdr; i < hdr + 24; i += 4) + nv_wo32(dev, chan->ramin->gpuobj, i/4, 0); +- dev_priv->engine.instmem.finish_access(dev); ++ dev_priv->engine.instmem.flush(dev); + + nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); + } +diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c +index 5f21df3..b7ad258 100644 +--- a/drivers/gpu/drm/nouveau/nv50_instmem.c ++++ b/drivers/gpu/drm/nouveau/nv50_instmem.c +@@ -35,8 +35,6 @@ struct nv50_instmem_priv { + struct nouveau_gpuobj_ref *pramin_pt; + struct nouveau_gpuobj_ref *pramin_bar; + struct nouveau_gpuobj_ref *fb_bar; +- +- bool last_access_wr; + }; + + #define NV50_INSTMEM_PAGE_SHIFT 12 +@@ -147,7 +145,7 @@ nv50_instmem_init(struct drm_device *dev) + if (ret) + return ret; + +- if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base)) ++ if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base)) + return -ENOMEM; + + /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */ +@@ -262,23 +260,18 @@ nv50_instmem_init(struct drm_device *dev) + + /* Assume that praying isn't enough, check that we can re-read the + * entire fake channel back from the PRAMIN BAR */ +- dev_priv->engine.instmem.prepare_access(dev, false); + for (i = 0; i < c_size; i += 4) { + if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) { + NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n", + i); +- dev_priv->engine.instmem.finish_access(dev); + return -EINVAL; + } + } +- dev_priv->engine.instmem.finish_access(dev); + + nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700); + + /* Global PRAMIN heap */ +- if (nouveau_mem_init_heap(&dev_priv->ramin_heap, +- c_size, dev_priv->ramin_size - c_size)) { +- dev_priv->ramin_heap = NULL; ++ if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) { + NV_ERROR(dev, "Failed to init RAMIN heap\n"); + } + +@@ -321,7 +314,7 @@ nv50_instmem_takedown(struct drm_device *dev) + nouveau_gpuobj_del(dev, &chan->vm_pd); + nouveau_gpuobj_ref_del(dev, &chan->ramfc); + nouveau_gpuobj_ref_del(dev, &chan->ramin); +- nouveau_mem_takedown(&chan->ramin_heap); ++ drm_mm_takedown(&chan->ramin_heap); + + dev_priv->fifos[0] = dev_priv->fifos[127] = NULL; + kfree(chan); +@@ -436,14 +429,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) + return -EINVAL; + +- NV_DEBUG(dev, "st=0x%0llx sz=0x%0llx\n", ++ NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", + gpuobj->im_pramin->start, gpuobj->im_pramin->size); + + pte = (gpuobj->im_pramin->start >> 12) << 1; + pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; + vram = gpuobj->im_backing_start; + +- NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n", ++ NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", + gpuobj->im_pramin->start, pte, pte_end); + NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); + +@@ -453,27 +446,15 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + vram |= 0x30; + } + +- dev_priv->engine.instmem.prepare_access(dev, true); + while (pte < pte_end) { + nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram)); + nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram)); + vram += NV50_INSTMEM_PAGE_SIZE; + } +- dev_priv->engine.instmem.finish_access(dev); +- +- nv_wr32(dev, 0x100c80, 0x00040001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (1)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } ++ dev_priv->engine.instmem.flush(dev); + +- nv_wr32(dev, 0x100c80, 0x00060001); +- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); +- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); +- return -EBUSY; +- } ++ nv50_vm_flush(dev, 4); ++ nv50_vm_flush(dev, 6); + + gpuobj->im_bound = 1; + return 0; +@@ -492,36 +473,36 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) + pte = (gpuobj->im_pramin->start >> 12) << 1; + pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; + +- dev_priv->engine.instmem.prepare_access(dev, true); + while (pte < pte_end) { + nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); + nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); + } +- dev_priv->engine.instmem.finish_access(dev); ++ dev_priv->engine.instmem.flush(dev); + + gpuobj->im_bound = 0; + return 0; + } + + void +-nv50_instmem_prepare_access(struct drm_device *dev, bool write) ++nv50_instmem_flush(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; +- +- priv->last_access_wr = write; ++ nv_wr32(dev, 0x00330c, 0x00000001); ++ if (!nv_wait(0x00330c, 0x00000001, 0x00000000)) ++ NV_ERROR(dev, "PRAMIN flush timeout\n"); + } + + void +-nv50_instmem_finish_access(struct drm_device *dev) ++nv84_instmem_flush(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; +- +- if (priv->last_access_wr) { +- nv_wr32(dev, 0x070000, 0x00000001); +- if (!nv_wait(0x070000, 0x00000001, 0x00000000)) +- NV_ERROR(dev, "PRAMIN flush timeout\n"); +- } ++ nv_wr32(dev, 0x070000, 0x00000001); ++ if (!nv_wait(0x070000, 0x00000001, 0x00000000)) ++ NV_ERROR(dev, "PRAMIN flush timeout\n"); + } + ++void ++nv50_vm_flush(struct drm_device *dev, int engine) ++{ ++ nv_wr32(dev, 0x100c80, (engine << 16) | 1); ++ if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) ++ NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); ++} +diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c +index 812778d..bcd4cf8 100644 +--- a/drivers/gpu/drm/nouveau/nv50_sor.c ++++ b/drivers/gpu/drm/nouveau/nv50_sor.c +@@ -37,52 +37,32 @@ + #include "nv50_display.h" + + static void +-nv50_sor_disconnect(struct nouveau_encoder *nv_encoder) ++nv50_sor_disconnect(struct drm_encoder *encoder) + { +- struct drm_device *dev = to_drm_encoder(nv_encoder)->dev; ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *evo = dev_priv->evo; + int ret; + ++ if (!nv_encoder->crtc) ++ return; ++ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true); ++ + NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or); + +- ret = RING_SPACE(evo, 2); ++ ret = RING_SPACE(evo, 4); + if (ret) { + NV_ERROR(dev, "no space while disconnecting SOR\n"); + return; + } + BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); +- OUT_RING(evo, 0); +-} +- +-static void +-nv50_sor_dp_link_train(struct drm_encoder *encoder) +-{ +- struct drm_device *dev = encoder->dev; +- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); +- struct bit_displayport_encoder_table *dpe; +- int dpe_headerlen; +- +- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); +- if (!dpe) { +- NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or); +- return; +- } ++ OUT_RING (evo, 0); ++ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); ++ OUT_RING (evo, 0); + +- if (dpe->script0) { +- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); +- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0), +- nv_encoder->dcb); +- } +- +- if (!nouveau_dp_link_train(encoder)) +- NV_ERROR(dev, "SOR-%d: link training failed\n", nv_encoder->or); +- +- if (dpe->script1) { +- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or); +- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1), +- nv_encoder->dcb); +- } ++ nv_encoder->crtc = NULL; ++ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; + } + + static void +@@ -94,14 +74,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) + uint32_t val; + int or = nv_encoder->or; + +- NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode); ++ NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode); + + nv_encoder->last_dpms = mode; + list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nvenc = nouveau_encoder(enc); + + if (nvenc == nv_encoder || +- nvenc->disconnect != nv50_sor_disconnect || ++ (nvenc->dcb->type != OUTPUT_TMDS && ++ nvenc->dcb->type != OUTPUT_LVDS && ++ nvenc->dcb->type != OUTPUT_DP) || + nvenc->dcb->or != nv_encoder->dcb->or) + continue; + +@@ -133,8 +115,22 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) + nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or))); + } + +- if (nv_encoder->dcb->type == OUTPUT_DP && mode == DRM_MODE_DPMS_ON) +- nv50_sor_dp_link_train(encoder); ++ if (nv_encoder->dcb->type == OUTPUT_DP) { ++ struct nouveau_i2c_chan *auxch; ++ ++ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); ++ if (!auxch) ++ return; ++ ++ if (mode == DRM_MODE_DPMS_ON) { ++ u8 status = DP_SET_POWER_D0; ++ nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); ++ nouveau_dp_link_train(encoder); ++ } else { ++ u8 status = DP_SET_POWER_D3; ++ nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); ++ } ++ } + } + + static void +@@ -196,7 +192,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + uint32_t mode_ctl = 0; + int ret; + +- NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or); ++ NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n", ++ nv_encoder->or, nv_encoder->dcb->type, crtc->index); + + nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); + +@@ -239,6 +236,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + } + BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); + OUT_RING(evo, mode_ctl); ++ ++ nv_encoder->crtc = encoder->crtc; ++} ++ ++static struct drm_crtc * ++nv50_sor_crtc_get(struct drm_encoder *encoder) ++{ ++ return nouveau_encoder(encoder)->crtc; + } + + static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = { +@@ -249,7 +254,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = { + .prepare = nv50_sor_prepare, + .commit = nv50_sor_commit, + .mode_set = nv50_sor_mode_set, +- .detect = NULL ++ .get_crtc = nv50_sor_crtc_get, ++ .detect = NULL, ++ .disable = nv50_sor_disconnect + }; + + static void +@@ -272,32 +279,22 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = { + }; + + int +-nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) ++nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry) + { + struct nouveau_encoder *nv_encoder = NULL; ++ struct drm_device *dev = connector->dev; + struct drm_encoder *encoder; +- bool dum; + int type; + + NV_DEBUG_KMS(dev, "\n"); + + switch (entry->type) { + case OUTPUT_TMDS: +- NV_INFO(dev, "Detected a TMDS output\n"); ++ case OUTPUT_DP: + type = DRM_MODE_ENCODER_TMDS; + break; + case OUTPUT_LVDS: +- NV_INFO(dev, "Detected a LVDS output\n"); + type = DRM_MODE_ENCODER_LVDS; +- +- if (nouveau_bios_parse_lvds_table(dev, 0, &dum, &dum)) { +- NV_ERROR(dev, "Failed parsing LVDS table\n"); +- return -EINVAL; +- } +- break; +- case OUTPUT_DP: +- NV_INFO(dev, "Detected a DP output\n"); +- type = DRM_MODE_ENCODER_TMDS; + break; + default: + return -EINVAL; +@@ -310,8 +307,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) + + nv_encoder->dcb = entry; + nv_encoder->or = ffs(entry->or) - 1; +- +- nv_encoder->disconnect = nv50_sor_disconnect; ++ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; + + drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type); + drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs); +@@ -342,5 +338,6 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) + nv_encoder->dp.mc_unknown = 5; + } + ++ drm_mode_connector_attach_encoder(connector, encoder); + return 0; + } +diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h +index 5998c35..ad64673 100644 +--- a/drivers/gpu/drm/nouveau/nvreg.h ++++ b/drivers/gpu/drm/nouveau/nvreg.h +@@ -147,28 +147,6 @@ + # define NV_VIO_GX_DONT_CARE_INDEX 0x07 + # define NV_VIO_GX_BIT_MASK_INDEX 0x08 + +-#define NV_PFB_BOOT_0 0x00100000 +-#define NV_PFB_CFG0 0x00100200 +-#define NV_PFB_CFG1 0x00100204 +-#define NV_PFB_CSTATUS 0x0010020C +-#define NV_PFB_REFCTRL 0x00100210 +-# define NV_PFB_REFCTRL_VALID_1 (1 << 31) +-#define NV_PFB_PAD 0x0010021C +-# define NV_PFB_PAD_CKE_NORMAL (1 << 0) +-#define NV_PFB_TILE_NV10 0x00100240 +-#define NV_PFB_TILE_SIZE_NV10 0x00100244 +-#define NV_PFB_REF 0x001002D0 +-# define NV_PFB_REF_CMD_REFRESH (1 << 0) +-#define NV_PFB_PRE 0x001002D4 +-# define NV_PFB_PRE_CMD_PRECHARGE (1 << 0) +-#define NV_PFB_CLOSE_PAGE2 0x0010033C +-#define NV_PFB_TILE_NV40 0x00100600 +-#define NV_PFB_TILE_SIZE_NV40 0x00100604 +- +-#define NV_PEXTDEV_BOOT_0 0x00101000 +-# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12) +-#define NV_PEXTDEV_BOOT_3 0x0010100c +- + #define NV_PCRTC_INTR_0 0x00600100 + # define NV_PCRTC_INTR_0_VBLANK (1 << 0) + #define NV_PCRTC_INTR_EN_0 0x00600140 |