Merge remote branch 'nouveau/for-airlied' of ../drm-nouveau-next into drm-core-next
authorDave Airlie <airlied@redhat.com>
Mon, 2 Aug 2010 00:31:47 +0000 (10:31 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 2 Aug 2010 00:31:47 +0000 (10:31 +1000)
* 'nouveau/for-airlied' of ../drm-nouveau-next: (77 commits)
  drm/nouveau: set TASK_(UN)INTERRUPTIBLE before schedule_timeout()
  drm/nv50: fix some not-error error messages
  drm/nouveau: introduce gpio engine
  drm/nv50: correct wait condition for instmem flush
  drm/nouveau: Fix TV-out detection on unposted cards lacking a usable DCB table.
  drm/nouveau: Get rid of the remaining VGA CRTC locking.
  drm/nouveau: Move display init to a new nouveau_engine.
  drm/nouveau: Put back the old 2-messages I2C slave test.
  drm/nouveau: Reset AGP before running the init scripts.
  drm/nv30: Init the PFB+0x3xx memory timing regs.
  drm/nouveau: disable hotplug detect around DP link training
  drm/nv50: add function to control GPIO IRQ reporting
  drm/nouveau: add nv_mask register accessor
  drm/nouveau: fix build without CONFIG_ACPI
  drm/nouveau: Reset CRTC owner to 0 before BIOS init.
  drm/nouveau: No need to lock/unlock the VGA CRTC regs all the time.
  drm/nouveau: Remove useless CRTC_OWNER logging.
  drm/nouveau: Add some generic I2C gadget detection code.
  drm/i2c/ch7006: Don't assume that the specified config points to static memory.
  drm/nv04-nv3x: Implement init-compute-mem.
  ...

Conflicts:
drivers/gpu/drm/nouveau/nouveau_bios.c

55 files changed:
drivers/gpu/drm/i2c/ch7006_drv.c
drivers/gpu/drm/i2c/ch7006_priv.h
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_calc.c
drivers/gpu/drm/nouveau/nouveau_channel.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_dma.c
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_encoder.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_grctx.c [deleted file]
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_i2c.h
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_notifier.c
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv04_crtc.c
drivers/gpu/drm/nouveau/nv04_dac.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_display.c
drivers/gpu/drm/nouveau/nv04_fifo.c
drivers/gpu/drm/nouveau/nv04_graph.c
drivers/gpu/drm/nouveau/nv04_instmem.c
drivers/gpu/drm/nouveau/nv04_mc.c
drivers/gpu/drm/nouveau/nv04_tv.c
drivers/gpu/drm/nouveau/nv10_fifo.c
drivers/gpu/drm/nouveau/nv10_gpio.c [moved from drivers/gpu/drm/nouveau/nv17_gpio.c with 95% similarity]
drivers/gpu/drm/nouveau/nv17_tv.c
drivers/gpu/drm/nouveau/nv20_graph.c
drivers/gpu/drm/nouveau/nv30_fb.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv40_fifo.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/nouveau/nv40_mc.c
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_dac.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_display.h
drivers/gpu/drm/nouveau/nv50_fifo.c
drivers/gpu/drm/nouveau/nv50_gpio.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_instmem.c
drivers/gpu/drm/nouveau/nv50_sor.c
drivers/gpu/drm/nouveau/nvreg.h

index 81681a07a8060cbdb980765fca9edfc3a270d7ca..833b35f44a7705a336d432940c393016de7cd77d 100644 (file)
@@ -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",
index b06d3d93d8acb3facfb607691a2d61f11409a025..1c6d2e3bd96f154b636f5b15b34766565143ebd1 100644 (file)
@@ -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;
index acd31ed861eff4d366a528fec79f37f60b4d77ec..2405d5ef0ca735c351a677064575c838d9000e42 100644 (file)
@@ -9,10 +9,10 @@ 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 \
+             nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o \
              nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
              nv04_graph.o nv10_graph.o nv20_graph.o \
              nv40_graph.o nv50_graph.o \
@@ -22,7 +22,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nv50_cursor.o nv50_display.o nv50_fbcon.o \
              nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
              nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
-             nv17_gpio.o nv50_gpio.o \
+             nv10_gpio.o nv50_gpio.o \
             nv50_calc.o
 
 nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
index d4bcca8a5133b2a4565b8f7d794b4d558da5557e..c17a055ee3e57c3a356f2fd4d3b85d4432f7d4e5 100644 (file)
@@ -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;
+}
index e492919faf44167b14b97da9537f4aa881eb7969..b59f348f14fc321d83664022493d3d6c6f3ab6c5 100644 (file)
@@ -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);
@@ -2795,12 +3136,13 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         */
 
        struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
+       struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
        const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
        int i;
 
        if (dev_priv->card_type != NV_50) {
                NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
-               return -ENODEV;
+               return 1;
        }
 
        if (!iexec->execute)
@@ -2815,7 +3157,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n",
                        offset, gpio->tag, gpio->state_default);
                if (bios->execute)
-                       nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default);
+                       pgpio->set(bios->dev, gpio->tag, gpio->state_default);
 
                /* The NVIDIA binary driver doesn't appear to actually do
                 * any of this, my VBIOS does however.
@@ -2872,10 +3214,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 +3222,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 +3406,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 +3426,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 +3435,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 +3465,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 +3483,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 +5493,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 +5935,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 +6055,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 +6135,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 +6293,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);
 
@@ -6181,9 +6551,8 @@ nouveau_run_vbios_init(struct drm_device *dev)
        struct nvbios *bios = &dev_priv->vbios;
        int i, ret = 0;
 
-       NVLockVgaCrtcs(dev, false);
-       if (nv_two_heads(dev))
-               NVSetOwner(dev, bios->state.crtchead);
+       /* Reset the BIOS head to 0. */
+       bios->state.crtchead = 0;
 
        if (bios->major_version < 5)    /* BMP only */
                load_nv17_hw_sequencer_ucode(dev, bios);
@@ -6216,8 +6585,6 @@ nouveau_run_vbios_init(struct drm_device *dev)
                }
        }
 
-       NVLockVgaCrtcs(dev, true);
-
        return ret;
 }
 
@@ -6238,7 +6605,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 +6614,12 @@ nouveau_bios_posted(struct drm_device *dev)
                return true;
        }
 
-       was_locked = 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);
+
        return (htotal != 0);
 }
 
@@ -6263,8 +6628,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 +6647,27 @@ 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);
        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);
 
        /* allow subsequent scripts to execute */
        bios->execute = true;
index adf4ec2d06c0cd7086ce327bb8a71c87fe1b9dd2..024458a8d060193043852670b12beba84efa3c01 100644 (file)
@@ -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 {
index 9f5ab4677758e7ea1013a515ef9ff3f57379a8d7..3ca8343c15df9608c444140d9853603a94fd49a6 100644 (file)
@@ -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;
        }
index 88f9bc0941eb293a7cf727f261740900da5e14ba..ca85da78484653180ef6c03b64655df3e8117202 100644 (file)
@@ -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);
index 06555c7cde509104e8ce87c3b1b51bc54f17711c..90fdcda332be360ab07cb862c9a6ad533724a55c 100644 (file)
@@ -258,9 +258,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;
 
@@ -369,8 +367,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;
 
@@ -419,7 +415,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);
index 149ed224c3cb48c86c56e2f4b9bb18a599190d10..734e92635e83f103885cecbf8674d077a9df5cd9 100644 (file)
@@ -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;
 }
index 4ef38abc2d9cfa85b2f569b22e01d4c3f596c753..0d2e668ccfe5c52525117ca83a9e3791e0fef936 100644 (file)
@@ -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__ */
index 65c441a1999facfeeb3b9ca191198fad732583d8..2e3c6caa97eeefb70eda2b06f633aae520c19ceb 100644 (file)
@@ -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);
index deeb21c6865c84d6f490e7bc5e82fa7acf5cfc99..33742b11188bdcddbee6e6b51cb77de15718281a 100644 (file)
  */
 
 #include "drmP.h"
+
 #include "nouveau_drv.h"
 #include "nouveau_i2c.h"
+#include "nouveau_connector.h"
 #include "nouveau_encoder.h"
 
 static int
@@ -270,13 +272,39 @@ bool
 nouveau_dp_link_train(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       uint8_t config[4];
-       uint8_t status[3];
+       struct nouveau_connector *nv_connector;
+       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");
+
+       nv_connector = nouveau_encoder_connector_get(nv_encoder);
+       if (!nv_connector)
+               return false;
+
+       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;
+       }
+
+       /* disable hotplug detect, this flips around on some panels during
+        * link training.
+        */
+       pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, 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 +431,15 @@ 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);
+       }
+
+       /* re-enable hotplug detect */
+       pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true);
+
        return eq_done;
 }
 
index 0fd8e10dbbdebe259539618562322f5eba48e02f..1de5eb53e0164be3cc81cf5a17f7969bc211e4ef 100644 (file)
 
 #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");
@@ -269,6 +259,13 @@ nouveau_pci_resume(struct pci_dev *pdev)
                return -1;
        pci_set_master(dev->pdev);
 
+       /* Make sure the AGP controller is in a consistent state */
+       if (dev_priv->gart_info.type == NOUVEAU_GART_AGP)
+               nouveau_mem_reset_agp(dev);
+
+       /* Make the CRTCs accessible */
+       engine->display.early_init(dev);
+
        NV_INFO(dev, "POSTing device...\n");
        ret = nouveau_run_vbios_init(dev);
        if (ret)
@@ -323,7 +320,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,11 +328,7 @@ nouveau_pci_resume(struct pci_dev *pdev)
                        NV_ERROR(dev, "Could not pin/map cursor.\n");
        }
 
-       if (dev_priv->card_type < NV_50) {
-               nv04_display_restore(dev);
-               NVLockVgaCrtcs(dev, false);
-       } else
-               nv50_display_init(dev);
+       engine->display.init(dev);
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
@@ -371,7 +363,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 +431,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();
 }
index c697191064894345efbbf76bf3bfd1fc83188270..d0a35d9ba522004d419dba43858593e3ff4e3f0e 100644 (file)
@@ -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 *);
 
@@ -358,6 +351,24 @@ struct nouveau_pgraph_engine {
                                  uint32_t size, uint32_t pitch);
 };
 
+struct nouveau_display_engine {
+       int (*early_init)(struct drm_device *);
+       void (*late_takedown)(struct drm_device *);
+       int (*create)(struct drm_device *);
+       int (*init)(struct drm_device *);
+       void (*destroy)(struct drm_device *);
+};
+
+struct nouveau_gpio_engine {
+       int  (*init)(struct drm_device *);
+       void (*takedown)(struct drm_device *);
+
+       int  (*get)(struct drm_device *, enum dcb_gpio_tag);
+       int  (*set)(struct drm_device *, enum dcb_gpio_tag, int state);
+
+       void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on);
+};
+
 struct nouveau_engine {
        struct nouveau_instmem_engine instmem;
        struct nouveau_mc_engine      mc;
@@ -365,6 +376,8 @@ struct nouveau_engine {
        struct nouveau_fb_engine      fb;
        struct nouveau_pgraph_engine  graph;
        struct nouveau_fifo_engine    fifo;
+       struct nouveau_display_engine display;
+       struct nouveau_gpio_engine    gpio;
 };
 
 struct nouveau_pll_vals {
@@ -500,11 +513,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 +541,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 +601,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 +620,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 +659,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 +681,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,17 +705,10 @@ 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 int  nouveau_mem_reset_agp(struct drm_device *);
 extern void nouveau_mem_close(struct drm_device *);
 extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev,
                                                    uint32_t addr,
@@ -857,11 +848,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 *dev, struct drm_connector *connector) { return -EINVAL; }
 #endif
 
 /* nouveau_backlight.c */
@@ -924,6 +917,10 @@ extern void nv10_fb_takedown(struct drm_device *);
 extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t,
                                      uint32_t, uint32_t);
 
+/* nv30_fb.c */
+extern int  nv30_fb_init(struct drm_device *);
+extern void nv30_fb_takedown(struct drm_device *);
+
 /* nv40_fb.c */
 extern int  nv40_fb_init(struct drm_device *);
 extern void nv40_fb_takedown(struct drm_device *);
@@ -1035,12 +1032,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 +1042,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 +1054,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 +1079,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,15 +1095,17 @@ 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_early_init(struct drm_device *);
+extern void nv04_display_late_takedown(struct drm_device *);
 extern int nv04_display_create(struct drm_device *);
+extern int nv04_display_init(struct drm_device *);
 extern void nv04_display_destroy(struct drm_device *);
-extern void nv04_display_restore(struct drm_device *);
 
 /* nv04_crtc.c */
 extern int nv04_crtc_create(struct drm_device *, int index);
@@ -1147,7 +1141,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 *,
@@ -1167,13 +1160,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
 extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
                                  struct drm_file *);
 
-/* nv17_gpio.c */
-int nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
-int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
+/* nv10_gpio.c */
+int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
+int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
 
 /* nv50_gpio.c */
+int nv50_gpio_init(struct drm_device *dev);
 int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
 int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
+void nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on);
 
 /* nv50_calc. */
 int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
@@ -1220,6 +1215,14 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val)
        iowrite32_native(val, dev_priv->mmio + reg);
 }
 
+static inline void nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val)
+{
+       u32 tmp = nv_rd32(dev, reg);
+       tmp &= ~mask;
+       tmp |= val;
+       nv_wr32(dev, reg, tmp);
+}
+
 static inline u8 nv_rd08(struct drm_device *dev, unsigned reg)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
index e1df8209cd0f58424c41fea37c4758801e1f4aad..a1a0d48ae70c04b95fd6e75b3d494e5a16e8ba12 100644 (file)
@@ -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;
index 257ea130ae13a3c7fa0c8d2ca5b60ab5ce79d706..2fb2444d23221d8684683dedb036b14f3034220d 100644 (file)
@@ -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;
index faddf53ff9ed79f0804735c151a28c3fb2d9a7ec..6b208ffafa8de1df0bdd5dd6ff6aede30f929341 100644 (file)
@@ -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;
 }
 
@@ -190,8 +186,6 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
        unsigned long timeout = jiffies + (3 * DRM_HZ);
        int ret = 0;
 
-       __set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
-
        while (1) {
                if (nouveau_fence_signalled(sync_obj, sync_arg))
                        break;
@@ -201,6 +195,8 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
                        break;
                }
 
+               __set_current_state(intr ? TASK_INTERRUPTIBLE
+                       : TASK_UNINTERRUPTIBLE);
                if (lazy)
                        schedule_timeout(1);
 
@@ -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;
 }
 
index 69c76cf934074b9ef962dc3f1e4c78f40b4bdf28..547f2c24c1e76ac38eaab50db207e5eaa5c59395 100644 (file)
@@ -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 (file)
index f731c5f..0000000
+++ /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));
-}
index 316a3c7e6eb492e6763fe6ec863a0c1347396eeb..cb0cb34440c6e835246136cd7f6ade3f29e71d21 100644 (file)
@@ -278,3 +278,45 @@ nouveau_i2c_find(struct drm_device *dev, int index)
        return i2c->chan;
 }
 
+bool
+nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr)
+{
+       uint8_t buf[] = { 0 };
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = buf,
+               },
+               {
+                       .addr = addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = buf,
+               }
+       };
+
+       return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
+}
+
+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 i;
+
+       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);
+                       return i;
+               }
+       }
+
+       NV_DEBUG(dev, "No devices found.\n");
+
+       return -ENODEV;
+}
index c8eaf7a9fcbbad17b7bea504d0613f2e6c75de9e..6dd2f8713cd16befce5d0ce9b75bc5f5a20d662c 100644 (file)
@@ -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);
index fb6b791506b2cf7ec0f243f48b3388dd2e728f48..a9f36ab256b72b535a098c8dd3aeed06dc9c2ea6 100644 (file)
 #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
@@ -474,26 +253,26 @@ void nouveau_mem_close(struct drm_device *dev)
                drm_mtrr_del(dev_priv->fb_mtrr,
                             pci_resource_start(dev->pdev, 1),
                             pci_resource_len(dev->pdev, 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;
        }
 
@@ -537,12 +316,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));
@@ -556,18 +341,36 @@ nouveau_mem_detect(struct drm_device *dev)
        return -ENOMEM;
 }
 
-#if __OS_HAS_AGP
-static void nouveau_mem_reset_agp(struct drm_device *dev)
+int
+nouveau_mem_reset_agp(struct drm_device *dev)
 {
-       uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable;
+#if __OS_HAS_AGP
+       uint32_t saved_pci_nv_1, pmc_enable;
+       int ret;
+
+       /* First of all, disable fast writes, otherwise if it's
+        * already enabled in the AGP bridge and we disable the card's
+        * AGP controller we might be locking ourselves out of it. */
+       if (dev->agp->acquired) {
+               struct drm_agp_info info;
+               struct drm_agp_mode mode;
+
+               ret = drm_agp_info(dev, &info);
+               if (ret)
+                       return ret;
+
+               mode.mode = info.mode & ~0x10;
+               ret = drm_agp_enable(dev, mode);
+               if (ret)
+                       return ret;
+       }
 
        saved_pci_nv_1 = nv_rd32(dev, NV04_PBUS_PCI_NV_1);
-       saved_pci_nv_19 = nv_rd32(dev, NV04_PBUS_PCI_NV_19);
 
        /* clear busmaster bit */
        nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1 & ~0x4);
-       /* clear SBA and AGP bits */
-       nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19 & 0xfffff0ff);
+       /* disable AGP */
+       nv_wr32(dev, NV04_PBUS_PCI_NV_19, 0);
 
        /* power cycle pgraph, if enabled */
        pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
@@ -579,11 +382,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev)
        }
 
        /* and restore (gives effect of resetting AGP) */
-       nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19);
        nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1);
-}
 #endif
 
+       return 0;
+}
+
 int
 nouveau_mem_init_agp(struct drm_device *dev)
 {
@@ -593,11 +397,6 @@ nouveau_mem_init_agp(struct drm_device *dev)
        struct drm_agp_mode mode;
        int ret;
 
-       if (nouveau_noagp)
-               return 0;
-
-       nouveau_mem_reset_agp(dev);
-
        if (!dev->agp->acquired) {
                ret = drm_agp_acquire(dev);
                if (ret) {
@@ -694,7 +493,8 @@ nouveau_mem_init(struct drm_device *dev)
 
        /* GART */
 #if !defined(__powerpc__) && !defined(__ia64__)
-       if (drm_device_is_agp(dev) && dev->agp) {
+       if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
+               nouveau_mem_reset_agp(dev);
                ret = nouveau_mem_init_agp(dev);
                if (ret)
                        NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
index 9537f3e30115fb16135794aa674fa2a65da7ecb7..3ec181ff50cea7a45b22a28a6ed43857b2a841cb 100644 (file)
@@ -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);
index e7c100ba63a16d2d3b45284de22f1073767758de..b6bcb254f4ab49ab123834d78f4e62e58ac0398a 100644 (file)
@@ -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.free_stack.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);
index 6ca80a3fe70db02084ed9730fe857b92345dd16f..9c1056cb8a90761415bd2f8e96303cd8ded234cf 100644 (file)
@@ -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
 
 #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
 #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
index 1d6ee8b55154c95aa763ed278c31b14da32fa9a7..491767fe4fcfd3b705c3bdb82b4ebeded1bfe9bb 100644 (file)
@@ -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;
        }
 
index b02a231d6937489fe972bfc813dc72d5d421aa70..ee3729e7823ba312001985790e54f4844610416d 100644 (file)
@@ -38,6 +38,7 @@
 #include "nv50_display.h"
 
 static void nouveau_stub_takedown(struct drm_device *dev) {}
+static int nouveau_stub_init(struct drm_device *dev) { return 0; }
 
 static int nouveau_init_engine_ptrs(struct drm_device *dev)
 {
@@ -54,8 +55,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;
@@ -85,6 +85,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.destroy_context    = nv04_fifo_destroy_context;
                engine->fifo.load_context       = nv04_fifo_load_context;
                engine->fifo.unload_context     = nv04_fifo_unload_context;
+               engine->display.early_init      = nv04_display_early_init;
+               engine->display.late_takedown   = nv04_display_late_takedown;
+               engine->display.create          = nv04_display_create;
+               engine->display.init            = nv04_display_init;
+               engine->display.destroy         = nv04_display_destroy;
+               engine->gpio.init               = nouveau_stub_init;
+               engine->gpio.takedown           = nouveau_stub_takedown;
+               engine->gpio.get                = NULL;
+               engine->gpio.set                = NULL;
+               engine->gpio.irq_enable         = NULL;
                break;
        case 0x10:
                engine->instmem.init            = nv04_instmem_init;
@@ -95,8 +105,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;
@@ -128,6 +137,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.destroy_context    = nv10_fifo_destroy_context;
                engine->fifo.load_context       = nv10_fifo_load_context;
                engine->fifo.unload_context     = nv10_fifo_unload_context;
+               engine->display.early_init      = nv04_display_early_init;
+               engine->display.late_takedown   = nv04_display_late_takedown;
+               engine->display.create          = nv04_display_create;
+               engine->display.init            = nv04_display_init;
+               engine->display.destroy         = nv04_display_destroy;
+               engine->gpio.init               = nouveau_stub_init;
+               engine->gpio.takedown           = nouveau_stub_takedown;
+               engine->gpio.get                = nv10_gpio_get;
+               engine->gpio.set                = nv10_gpio_set;
+               engine->gpio.irq_enable         = NULL;
                break;
        case 0x20:
                engine->instmem.init            = nv04_instmem_init;
@@ -138,8 +157,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;
@@ -171,6 +189,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.destroy_context    = nv10_fifo_destroy_context;
                engine->fifo.load_context       = nv10_fifo_load_context;
                engine->fifo.unload_context     = nv10_fifo_unload_context;
+               engine->display.early_init      = nv04_display_early_init;
+               engine->display.late_takedown   = nv04_display_late_takedown;
+               engine->display.create          = nv04_display_create;
+               engine->display.init            = nv04_display_init;
+               engine->display.destroy         = nv04_display_destroy;
+               engine->gpio.init               = nouveau_stub_init;
+               engine->gpio.takedown           = nouveau_stub_takedown;
+               engine->gpio.get                = nv10_gpio_get;
+               engine->gpio.set                = nv10_gpio_set;
+               engine->gpio.irq_enable         = NULL;
                break;
        case 0x30:
                engine->instmem.init            = nv04_instmem_init;
@@ -181,15 +209,14 @@ 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;
                engine->timer.read              = nv04_timer_read;
                engine->timer.takedown          = nv04_timer_takedown;
-               engine->fb.init                 = nv10_fb_init;
-               engine->fb.takedown             = nv10_fb_takedown;
+               engine->fb.init                 = nv30_fb_init;
+               engine->fb.takedown             = nv30_fb_takedown;
                engine->fb.set_region_tiling    = nv10_fb_set_region_tiling;
                engine->graph.grclass           = nv30_graph_grclass;
                engine->graph.init              = nv30_graph_init;
@@ -214,6 +241,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.destroy_context    = nv10_fifo_destroy_context;
                engine->fifo.load_context       = nv10_fifo_load_context;
                engine->fifo.unload_context     = nv10_fifo_unload_context;
+               engine->display.early_init      = nv04_display_early_init;
+               engine->display.late_takedown   = nv04_display_late_takedown;
+               engine->display.create          = nv04_display_create;
+               engine->display.init            = nv04_display_init;
+               engine->display.destroy         = nv04_display_destroy;
+               engine->gpio.init               = nouveau_stub_init;
+               engine->gpio.takedown           = nouveau_stub_takedown;
+               engine->gpio.get                = nv10_gpio_get;
+               engine->gpio.set                = nv10_gpio_set;
+               engine->gpio.irq_enable         = NULL;
                break;
        case 0x40:
        case 0x60:
@@ -225,8 +262,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;
@@ -258,6 +294,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.destroy_context    = nv40_fifo_destroy_context;
                engine->fifo.load_context       = nv40_fifo_load_context;
                engine->fifo.unload_context     = nv40_fifo_unload_context;
+               engine->display.early_init      = nv04_display_early_init;
+               engine->display.late_takedown   = nv04_display_late_takedown;
+               engine->display.create          = nv04_display_create;
+               engine->display.init            = nv04_display_init;
+               engine->display.destroy         = nv04_display_destroy;
+               engine->gpio.init               = nouveau_stub_init;
+               engine->gpio.takedown           = nouveau_stub_takedown;
+               engine->gpio.get                = nv10_gpio_get;
+               engine->gpio.set                = nv10_gpio_set;
+               engine->gpio.irq_enable         = NULL;
                break;
        case 0x50:
        case 0x80: /* gotta love NVIDIA's consistency.. */
@@ -271,8 +317,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;
@@ -300,6 +348,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.destroy_context    = nv50_fifo_destroy_context;
                engine->fifo.load_context       = nv50_fifo_load_context;
                engine->fifo.unload_context     = nv50_fifo_unload_context;
+               engine->display.early_init      = nv50_display_early_init;
+               engine->display.late_takedown   = nv50_display_late_takedown;
+               engine->display.create          = nv50_display_create;
+               engine->display.init            = nv50_display_init;
+               engine->display.destroy         = nv50_display_destroy;
+               engine->gpio.init               = nv50_gpio_init;
+               engine->gpio.takedown           = nouveau_stub_takedown;
+               engine->gpio.get                = nv50_gpio_get;
+               engine->gpio.set                = nv50_gpio_set;
+               engine->gpio.irq_enable         = nv50_gpio_irq_enable;
                break;
        default:
                NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
@@ -407,11 +465,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 +474,17 @@ 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);
 
+       /* Make the CRTCs and I2C buses accessible */
+       ret = engine->display.early_init(dev);
+       if (ret)
+               goto out;
+
        /* 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_display_early;
 
        ret = nouveau_mem_detect(dev);
        if (ret)
@@ -461,10 +516,15 @@ nouveau_card_init(struct drm_device *dev)
        if (ret)
                goto out_gpuobj;
 
+       /* PGPIO */
+       ret = engine->gpio.init(dev);
+       if (ret)
+               goto out_mc;
+
        /* PTIMER */
        ret = engine->timer.init(dev);
        if (ret)
-               goto out_mc;
+               goto out_gpio;
 
        /* PFB */
        ret = engine->fb.init(dev);
@@ -485,12 +545,16 @@ nouveau_card_init(struct drm_device *dev)
                        goto out_graph;
        }
 
+       ret = engine->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 +568,18 @@ 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:
+       engine->display.destroy(dev);
 out_fifo:
        if (!nouveau_noaccel)
                engine->fifo.takedown(dev);
@@ -543,6 +590,8 @@ out_fb:
        engine->fb.takedown(dev);
 out_timer:
        engine->timer.takedown(dev);
+out_gpio:
+       engine->gpio.takedown(dev);
 out_mc:
        engine->mc.takedown(dev);
 out_gpuobj:
@@ -556,6 +605,8 @@ out_gpuobj_early:
        nouveau_gpuobj_late_takedown(dev);
 out_bios:
        nouveau_bios_takedown(dev);
+out_display_early:
+       engine->display.late_takedown(dev);
 out:
        vga_client_register(dev->pdev, NULL, NULL, NULL);
        return ret;
@@ -566,45 +617,39 @@ 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);
-
-       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;
-               }
+       nouveau_backlight_exit(dev);
 
-               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->gpio.takedown(dev);
+       engine->mc.takedown(dev);
+       engine->display.late_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 +736,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 +745,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);
@@ -773,11 +818,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
        NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
                dev_priv->card_type, reg0);
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               int ret = nouveau_remove_conflicting_drivers(dev);
-               if (ret)
-                       return ret;
-       }
+       ret = nouveau_remove_conflicting_drivers(dev);
+       if (ret)
+               return ret;
 
        /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
        if (dev_priv->card_type >= NV_40) {
@@ -812,46 +855,26 @@ 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;
+       struct nouveau_engine *engine = &dev_priv->engine;
 
-       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);
+       engine->display.destroy(dev);
+       nouveau_card_takedown(dev);
 
        iounmap(dev_priv->mmio);
        iounmap(dev_priv->ramin);
@@ -867,8 +890,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 +958,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);
index eba687f1099e24fcb164eb7a3f3e18550acc0508..1c20c08ce67c33685eb433644679209bf31874ba 100644 (file)
@@ -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
index 1cb19e3acb554a998765c98a4aa31c708cd36caf..ea3627041ecf8e7eb4a59199d8c1c7e1e64fd437 100644 (file)
@@ -220,6 +220,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
        struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
        uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder);
        uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput,
@@ -251,22 +252,21 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
                nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf);
        }
 
-       saved_gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1);
-       saved_gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0);
+       saved_gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1);
+       saved_gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0);
 
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV);
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV);
+       gpio->set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV);
+       gpio->set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV);
 
        msleep(4);
 
        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;
 
@@ -304,8 +304,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
                nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4);
        nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2);
 
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC1, saved_gpio1);
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC0, saved_gpio0);
+       gpio->set(dev, DCB_GPIO_TVDAC1, saved_gpio1);
+       gpio->set(dev, DCB_GPIO_TVDAC0, saved_gpio0);
 
        return sample;
 }
@@ -315,9 +315,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 +333,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 +434,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 +518,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 +546,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;
 }
index 41634d4752fe08f6309d81c0b81ff0b7a65cc64f..3311f3a8c8180b9bd3eeee6e5571f7703a6d9bdf 100644 (file)
@@ -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;
 }
index c7898b4f6dfbe0e1fb440452368d22077a0b083d..9e28cf772e3cd482af0c1d048634470d0bdf3b2d 100644 (file)
@@ -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,40 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
                else
                        dev_priv->crtc_owner = 0x0;
        }
+}
+
+int
+nv04_display_early_init(struct drm_device *dev)
+{
+       /* Make the I2C buses accessible. */
+       if (!nv_gf4_disp_arch(dev)) {
+               uint32_t pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
+
+               if (!(pmc_enable & 1))
+                       nv_wr32(dev, NV03_PMC_ENABLE, pmc_enable | 1);
+       }
 
-ownerknown:
-       NV_INFO(dev, "Initial CRTC_OWNER is %d\n", dev_priv->crtc_owner);
+       /* Unlock the VGA CRTCs. */
+       NVLockVgaCrtcs(dev, false);
+
+       /* Make sure the CRTCs aren't in slaved mode. */
+       if (nv_two_heads(dev)) {
+               nv04_display_store_initial_head_owner(dev);
+               NVSetOwner(dev, 0);
+       }
+
+       return 0;
+}
+
+void
+nv04_display_late_takedown(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (nv_two_heads(dev))
+               NVSetOwner(dev, 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);
+       NVLockVgaCrtcs(dev, true);
 }
 
 int
@@ -94,14 +114,13 @@ 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))
-               nv04_display_store_initial_head_owner(dev);
        nouveau_hw_save_vga_fonts(dev, 1);
 
        drm_mode_config_init(dev);
@@ -132,19 +151,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 +178,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);
 
@@ -191,8 +218,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;
 
@@ -207,15 +232,12 @@ nv04_display_destroy(struct drm_device *dev)
        nouveau_hw_save_vga_fonts(dev, 0);
 }
 
-void
-nv04_display_restore(struct drm_device *dev)
+int
+nv04_display_init(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct drm_encoder *encoder;
        struct drm_crtc *crtc;
 
-       NVLockVgaCrtcs(dev, false);
-
        /* meh.. modeset apparently doesn't setup all the regs and depends
         * on pre-existing state, for now load the state of the card *before*
         * nouveau was loaded, and then do a modeset.
@@ -233,12 +255,6 @@ 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);
+       return 0;
 }
 
index 66fe55983b6e3b7b9cf7b14700a7c1ba5b5681c9..06cedd99c26a3a72e4fc18d1f743a19a374a8706 100644 (file)
@@ -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]) {
index 618355e9cdd5602f7ea57e8c31afbcaaf2d4b1b5..c8973421b635529fcb027539aa2f7bbffde81546 100644 (file)
@@ -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;
 }
 
index a3b9563a6f60c4f933cd9caf687da307eaac90ae..4408232d33f179805205763974beede957ddd6f1 100644 (file)
@@ -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)
 {
 }
 
index 617ed1e052692cc6f80746560e0b2d494c58d776..2af43a1cb2ec00e698dbbd320e1bdffeaee3dab3 100644 (file)
@@ -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;
 }
 
index c4e3404337d4708e7b60c57e538908455f2ac235..94e299cef0b2624521b69251e4e1452945238728 100644 (file)
 
 #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;
 }
index 7aeabf262bc0a43affe3c1fdad393e9301d95263..7a4069cf5d0b835caccd983722bb640df7f6e351 100644 (file)
@@ -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;
similarity index 95%
rename from drivers/gpu/drm/nouveau/nv17_gpio.c
rename to drivers/gpu/drm/nouveau/nv10_gpio.c
index 2e58c331e9b7dcc6830a63d3d8988d375a9d5179..007fc29e2f86130987ee5759894ed447f2fa1d93 100644 (file)
@@ -55,7 +55,7 @@ get_gpio_location(struct dcb_gpio_entry *ent, uint32_t *reg, uint32_t *shift,
 }
 
 int
-nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
+nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
 {
        struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
        uint32_t reg, shift, mask, value;
@@ -72,7 +72,7 @@ nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
 }
 
 int
-nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
+nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
 {
        struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
        uint32_t reg, shift, mask, value;
index 74c880374fb92a5593583b4d077bac002ec76c3c..44fefb0c7083caf5c4e77011675927dc3d60aec6 100644 (file)
@@ -37,6 +37,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
        uint32_t testval, regoffset = nv04_dac_output_offset(encoder);
        uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end,
                fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c;
@@ -52,8 +53,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
        head = (dacclk & 0x100) >> 8;
 
        /* Save the previous state. */
-       gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1);
-       gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0);
+       gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1);
+       gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0);
        fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL);
        fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START);
        fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END);
@@ -64,8 +65,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
        ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c);
 
        /* Prepare the DAC for load detection.  */
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC1, true);
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC0, true);
+       gpio->set(dev, DCB_GPIO_TVDAC1, true);
+       gpio->set(dev, DCB_GPIO_TVDAC0, true);
 
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343);
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047);
@@ -110,12 +111,27 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end);
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start);
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal);
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC1, gpio1);
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC0, gpio0);
+       gpio->set(dev, DCB_GPIO_TVDAC1, gpio1);
+       gpio->set(dev, DCB_GPIO_TVDAC0, gpio0);
 
        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 +140,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 +178,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 +322,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
@@ -307,6 +336,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
 static void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
        struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;
        struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
 
@@ -331,8 +362,8 @@ static void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)
 
        nv_load_ptv(dev, regs, 200);
 
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON);
-       nv17_gpio_set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON);
+       gpio->set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON);
+       gpio->set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON);
 
        nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
 }
@@ -744,8 +775,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 +807,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;
 }
index fe2349b115f0f3f8906c42baaae6774a7a8270ce..17f309b36c910060a355af6d1ada2e6ca6fc7cfd 100644 (file)
@@ -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/nv30_fb.c b/drivers/gpu/drm/nouveau/nv30_fb.c
new file mode 100644 (file)
index 0000000..9d35c8b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+
+static int
+calc_ref(int b, int l, int i)
+{
+       int j, x = 0;
+
+       for (j = 0; j < 4; j++) {
+               int n = (b >> (8 * j) & 0xf);
+               int m = (l >> (8 * i) & 0xff) + 2 * (n & 0x8 ? n - 0x10 : n);
+
+               x |= (0x80 | (m & 0x1f)) << (8 * j);
+       }
+
+       return x;
+}
+
+int
+nv30_fb_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+       int i, j;
+
+       pfb->num_tiles = NV10_PFB_TILE__SIZE;
+
+       /* Turn all the tiling regions off. */
+       for (i = 0; i < pfb->num_tiles; i++)
+               pfb->set_region_tiling(dev, i, 0, 0, 0);
+
+       /* Init the memory timing regs at 0x10037c/0x1003ac */
+       if (dev_priv->chipset == 0x30 ||
+           dev_priv->chipset == 0x31 ||
+           dev_priv->chipset == 0x35) {
+               /* Related to ROP count */
+               int n = (dev_priv->chipset == 0x31 ? 2 : 4);
+               int b = (dev_priv->chipset > 0x30 ?
+                        nv_rd32(dev, 0x122c) & 0xf : 0);
+               int l = nv_rd32(dev, 0x1003d0);
+
+               for (i = 0; i < n; i++) {
+                       for (j = 0; j < 3; j++)
+                               nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j,
+                                       calc_ref(b, l, j));
+
+                       for (j = 0; j < 2; j++)
+                               nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j,
+                                       calc_ref(b, l, j));
+               }
+       }
+
+       return 0;
+}
+
+void
+nv30_fb_takedown(struct drm_device *dev)
+{
+}
index 500ccfd3a0b8c664b62cdc308ebaff0cc95d3042..2b67f1835c3942c4fddbe63b2b84a9050df81134 100644 (file)
@@ -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,
index 65b13b54c5ae0e478fc3dac2aa0deb2274775b4b..fd7d2b5013167f58e92b0c5859fd965564f2e53d 100644 (file)
@@ -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[] = {
index 2a3495e848e9b96e548339e5d41eb1fd5a7c2985..e4e72c12ab6ac3c10a73661b5be8a871101bf714 100644 (file)
@@ -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);
index b4e4a3b05eaef64151a1b8317774bd9c2863e34e..5d11ea101666dc6eb3e39bfeeaee035f44c633c0 100644 (file)
@@ -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
index 1fd9537beff60c404ebded245764edb3e1845802..1bc085962945056aba2e5ea5acfc8c72a5ca5da2 100644 (file)
 #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;
 }
 
index 580a5d10be9322cb581fc357a3b5215e7a3fcf10..f13ad0de9c8ff8a4b1d55e0d4329c7e6b1c9e997 100644 (file)
@@ -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);
@@ -178,14 +177,26 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
        return 0;
 }
 
+int
+nv50_display_early_init(struct drm_device *dev)
+{
+       return 0;
+}
+
+void
+nv50_display_late_takedown(struct drm_device *dev)
+{
+}
+
 int
 nv50_display_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+       struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
        struct nouveau_channel *evo = dev_priv->evo;
        struct drm_connector *connector;
-       uint32_t val, ram_amount, hpd_en[2];
+       uint32_t val, ram_amount;
        uint64_t start;
        int ret, i;
 
@@ -366,26 +377,13 @@ nv50_display_init(struct drm_device *dev)
                                             NV50_PDISPLAY_INTR_EN_CLK_UNK40));
 
        /* enable hotplug interrupts */
-       hpd_en[0] = hpd_en[1] = 0;
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct nouveau_connector *conn = nouveau_connector(connector);
-               struct dcb_gpio_entry *gpio;
 
                if (conn->dcb->gpio_tag == 0xff)
                        continue;
 
-               gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag);
-               if (!gpio)
-                       continue;
-
-               hpd_en[gpio->line >> 4] |= (0x00010001 << (gpio->line & 0xf));
-       }
-
-       nv_wr32(dev, 0xe054, 0xffffffff);
-       nv_wr32(dev, 0xe050, hpd_en[0]);
-       if (dev_priv->chipset >= 0x90) {
-               nv_wr32(dev, 0xe074, 0xffffffff);
-               nv_wr32(dev, 0xe070, hpd_en[1]);
+               pgpio->irq_enable(dev, conn->dcb->gpio_tag, true);
        }
 
        return 0;
@@ -465,6 +463,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 +506,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 +525,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);
@@ -538,7 +543,8 @@ int nv50_display_create(struct drm_device *dev)
        return 0;
 }
 
-int nv50_display_destroy(struct drm_device *dev)
+void
+nv50_display_destroy(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
@@ -548,135 +554,30 @@ int nv50_display_destroy(struct drm_device *dev)
 
        nv50_display_disable(dev);
        nv50_evo_channel_del(&dev_priv->evo);
-
-       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);
-   &