aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig11
-rw-r--r--drivers/gpu/drm/nouveau/Makefile12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c38
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c910
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c32
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_calc.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c32
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c417
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c128
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c41
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h190
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h16
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c39
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c66
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_grctx.c160
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hw.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.c83
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.h11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c341
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_notifier.c30
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c105
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_reg.h109
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c58
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c340
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c20
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c20
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dac.c50
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dfp.c110
-rw-r--r--drivers/gpu/drm/nouveau/nv04_display.c90
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fifo.c20
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c5
-rw-r--r--drivers/gpu/drm/nouveau/nv04_instmem.c21
-rw-r--r--drivers/gpu/drm/nouveau/nv04_mc.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv04_tv.c133
-rw-r--r--drivers/gpu/drm/nouveau/nv10_fifo.c10
-rw-r--r--drivers/gpu/drm/nouveau/nv10_gpio.c (renamed from drivers/gpu/drm/nouveau/nv17_gpio.c)4
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c175
-rw-r--r--drivers/gpu/drm/nouveau/nv17_tv.c69
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c100
-rw-r--r--drivers/gpu/drm/nouveau/nv30_fb.c95
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c8
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c60
-rw-r--r--drivers/gpu/drm/nouveau/nv40_mc.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c76
-rw-r--r--drivers/gpu/drm/nouveau/nv50_dac.c43
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c424
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.h6
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fifo.c126
-rw-r--r--drivers/gpu/drm/nouveau/nv50_gpio.c35
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c86
-rw-r--r--drivers/gpu/drm/nouveau/nv50_instmem.c72
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c105
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fb.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fifo.c96
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.c75
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_instmem.c235
-rw-r--r--drivers/gpu/drm/nouveau/nvreg.h22
63 files changed, 3370 insertions, 2287 deletions
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 1175429da10..d2d28048efb 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -1,6 +1,6 @@
config DRM_NOUVEAU
tristate "Nouveau (nVidia) cards"
- depends on DRM
+ depends on DRM && PCI
select FW_LOADER
select DRM_KMS_HELPER
select DRM_TTM
@@ -41,4 +41,13 @@ config DRM_I2C_CH7006
This driver is currently only useful if you're also using
the nouveau driver.
+
+config DRM_I2C_SIL164
+ tristate "Silicon Image sil164 TMDS transmitter"
+ default m if DRM_NOUVEAU
+ help
+ Support for sil164 and similar single-link (or dual-link
+ when used in pairs) TMDS transmitters, used in some nVidia
+ video cards.
+
endmenu
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index acd31ed861e..e9b06e4ef2a 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -9,20 +9,20 @@ 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_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
+ nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
+ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
nv04_graph.o nv10_graph.o nv20_graph.o \
- nv40_graph.o nv50_graph.o \
+ nv40_graph.o nv50_graph.o nvc0_graph.o \
nv40_grctx.o nv50_grctx.o \
- nv04_instmem.o nv50_instmem.o \
+ nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
nv50_crtc.o nv50_dac.o nv50_sor.o \
nv50_cursor.o nv50_display.o nv50_fbcon.o \
nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
- nv17_gpio.o nv50_gpio.o \
+ nv10_gpio.o nv50_gpio.o \
nv50_calc.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index d4bcca8a513..c17a055ee3e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -3,6 +3,7 @@
#include <linux/slab.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
+#include <acpi/video.h>
#include "drmP.h"
#include "drm.h"
@@ -11,6 +12,7 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
#include "nv50_display.h"
+#include "nouveau_connector.h"
#include <linux/vga_switcheroo.h>
@@ -42,7 +44,7 @@ static const char nouveau_dsm_muid[] = {
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
};
-static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result)
+static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_object_list input;
@@ -259,3 +261,37 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
{
return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
}
+
+int
+nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
+{
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+ struct acpi_device *acpidev;
+ acpi_handle handle;
+ int type, ret;
+ void *edid;
+
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_eDP:
+ type = ACPI_VIDEO_DISPLAY_LCD;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
+ if (!handle)
+ return -ENODEV;
+
+ ret = acpi_bus_get_device(handle, &acpidev);
+ if (ret)
+ return -ENODEV;
+
+ ret = acpi_video_get_edid(acpidev, type, -1, &edid);
+ if (ret < 0)
+ return ret;
+
+ nv_connector->edid = edid;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index e492919faf4..974b0f8ae04 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -28,6 +28,8 @@
#include "nouveau_hw.h"
#include "nouveau_encoder.h"
+#include <linux/io-mapping.h>
+
/* these defines are made up */
#define NV_CIO_CRE_44_HEADA 0x0
#define NV_CIO_CRE_44_HEADB 0x3
@@ -209,20 +211,20 @@ static struct methods shadow_methods[] = {
{ "PCIROM", load_vbios_pci, true },
{ "ACPI", load_vbios_acpi, true },
};
+#define NUM_SHADOW_METHODS ARRAY_SIZE(shadow_methods)
static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
{
- const int nr_methods = ARRAY_SIZE(shadow_methods);
struct methods *methods = shadow_methods;
int testscore = 3;
- int scores[nr_methods], i;
+ int scores[NUM_SHADOW_METHODS], i;
if (nouveau_vbios) {
- for (i = 0; i < nr_methods; i++)
+ for (i = 0; i < NUM_SHADOW_METHODS; i++)
if (!strcasecmp(nouveau_vbios, methods[i].desc))
break;
- if (i < nr_methods) {
+ if (i < NUM_SHADOW_METHODS) {
NV_INFO(dev, "Attempting to use BIOS image from %s\n",
methods[i].desc);
@@ -234,7 +236,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
}
- for (i = 0; i < nr_methods; i++) {
+ for (i = 0; i < NUM_SHADOW_METHODS; i++) {
NV_TRACE(dev, "Attempting to load BIOS image from %s\n",
methods[i].desc);
data[0] = data[1] = 0; /* avoid reuse of previous image */
@@ -245,7 +247,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
}
while (--testscore > 0) {
- for (i = 0; i < nr_methods; i++) {
+ for (i = 0; i < NUM_SHADOW_METHODS; i++) {
if (scores[i] == testscore) {
NV_TRACE(dev, "Using BIOS image from %s\n",
methods[i].desc);
@@ -920,7 +922,7 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
NV_ERROR(bios->dev,
"0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
offset, config, count);
- return -EINVAL;
+ return len;
}
configval = ROM32(bios->data[offset + 11 + config * 4]);
@@ -1022,7 +1024,7 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
NV_ERROR(bios->dev,
"0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
offset, config, count);
- return -EINVAL;
+ return len;
}
freq = ROM16(bios->data[offset + 12 + config * 2]);
@@ -1194,7 +1196,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
dpe = nouveau_bios_dp_table(dev, dcb, &dummy);
if (!dpe) {
NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset);
- return -EINVAL;
+ return 3;
}
switch (cond) {
@@ -1218,12 +1220,16 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
int ret;
auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index);
- if (!auxch)
- return -ENODEV;
+ if (!auxch) {
+ NV_ERROR(dev, "0x%04X: couldn't get auxch\n", offset);
+ return 3;
+ }
ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1);
- if (ret)
- return ret;
+ if (ret) {
+ NV_ERROR(dev, "0x%04X: auxch rd fail: %d\n", offset, ret);
+ return 3;
+ }
if (cond & 1)
iexec->execute = false;
@@ -1392,7 +1398,7 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
NV_ERROR(bios->dev,
"0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
offset, config, count);
- return -EINVAL;
+ return len;
}
freq = ROM32(bios->data[offset + 11 + config * 4]);
@@ -1452,6 +1458,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* "mask n" and OR it with "data n" before writing it back to the device
*/
+ struct drm_device *dev = bios->dev;
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2] >> 1;
uint8_t count = bios->data[offset + 3];
@@ -1466,9 +1473,11 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
"Count: 0x%02X\n",
offset, i2c_index, i2c_address, count);
- chan = init_i2c_device_find(bios->dev, i2c_index);
- if (!chan)
- return -ENODEV;
+ chan = init_i2c_device_find(dev, i2c_index);
+ if (!chan) {
+ NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
+ return len;
+ }
for (i = 0; i < count; i++) {
uint8_t reg = bios->data[offset + 4 + i * 3];
@@ -1479,8 +1488,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
I2C_SMBUS_READ, reg,
I2C_SMBUS_BYTE_DATA, &val);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ NV_ERROR(dev, "0x%04X: i2c rd fail: %d\n", offset, ret);
+ return len;
+ }
BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
"Mask: 0x%02X, Data: 0x%02X\n",
@@ -1494,8 +1505,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
I2C_SMBUS_WRITE, reg,
I2C_SMBUS_BYTE_DATA, &val);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
+ return len;
+ }
}
return len;
@@ -1520,6 +1533,7 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* "DCB I2C table entry index", set the register to "data n"
*/
+ struct drm_device *dev = bios->dev;
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2] >> 1;
uint8_t count = bios->data[offset + 3];
@@ -1534,9 +1548,11 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
"Count: 0x%02X\n",
offset, i2c_index, i2c_address, count);
- chan = init_i2c_device_find(bios->dev, i2c_index);
- if (!chan)
- return -ENODEV;
+ chan = init_i2c_device_find(dev, i2c_index);
+ if (!chan) {
+ NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
+ return len;
+ }
for (i = 0; i < count; i++) {
uint8_t reg = bios->data[offset + 4 + i * 2];
@@ -1553,8 +1569,10 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
I2C_SMBUS_WRITE, reg,
I2C_SMBUS_BYTE_DATA, &val);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
+ return len;
+ }
}
return len;
@@ -1577,6 +1595,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* address" on the I2C bus given by "DCB I2C table entry index"
*/
+ struct drm_device *dev = bios->dev;
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2] >> 1;
uint8_t count = bios->data[offset + 3];
@@ -1584,7 +1603,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
struct nouveau_i2c_chan *chan;
struct i2c_msg msg;
uint8_t data[256];
- int i;
+ int ret, i;
if (!iexec->execute)
return len;
@@ -1593,9 +1612,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
"Count: 0x%02X\n",
offset, i2c_index, i2c_address, count);
- chan = init_i2c_device_find(bios->dev, i2c_index);
- if (!chan)
- return -ENODEV;
+ chan = init_i2c_device_find(dev, i2c_index);
+ if (!chan) {
+ NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
+ return len;
+ }
for (i = 0; i < count; i++) {
data[i] = bios->data[offset + 4 + i];
@@ -1608,8 +1629,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
msg.flags = 0;
msg.len = count;
msg.buf = data;
- if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
- return -EIO;
+ ret = i2c_transfer(&chan->adapter, &msg, 1);
+ if (ret != 1) {
+ NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
+ return len;
+ }
}
return len;
@@ -1633,6 +1657,7 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* used -- see get_tmds_index_reg()
*/
+ struct drm_device *dev = bios->dev;
uint8_t mlv = bios->data[offset + 1];
uint32_t tmdsaddr = bios->data[offset + 2];
uint8_t mask = bios->data[offset + 3];
@@ -1647,8 +1672,10 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
offset, mlv, tmdsaddr, mask, data);
reg = get_tmds_index_reg(bios->dev, mlv);
- if (!reg)
- return -EINVAL;
+ if (!reg) {
+ NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset);
+ return 5;
+ }
bios_wr32(bios, reg,
tmdsaddr | NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE);
@@ -1678,6 +1705,7 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
* register is used -- see get_tmds_index_reg()
*/
+ struct drm_device *dev = bios->dev;
uint8_t mlv = bios->data[offset + 1];
uint8_t count = bios->data[offset + 2];
int len = 3 + count * 2;
@@ -1691,8 +1719,10 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
offset, mlv, count);
reg = get_tmds_index_reg(bios->dev, mlv);
- if (!reg)
- return -EINVAL;
+ if (!reg) {
+ NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset);
+ return len;
+ }
for (i = 0; i < count; i++) {
uint8_t tmdsaddr = bios->data[offset + 3 + i * 2];
@@ -1898,6 +1928,31 @@ init_condition_time(struct nvbios *bios, uint16_t offset,
}
static int
+init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+ /*
+ * INIT_LTIME opcode: 0x57 ('V')
+ *
+ * offset (8 bit): opcode
+ * offset + 1 (16 bit): time
+ *
+ * Sleep for "time" miliseconds.
+ */
+
+ unsigned time = ROM16(bios->data[offset + 1]);
+
+ if (!iexec->execute)
+ return 3;
+
+ BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n",
+ offset, time);
+
+ msleep(time);
+
+ return 3;
+}
+
+static int
init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec)
{
@@ -1965,6 +2020,64 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
}
static int
+init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+ /*
+ * INIT_I2C_IF opcode: 0x5E ('^')
+ *
+ * offset (8 bit): opcode
+ * offset + 1 (8 bit): DCB I2C table entry index
+ * offset + 2 (8 bit): I2C slave address
+ * offset + 3 (8 bit): I2C register
+ * offset + 4 (8 bit): mask
+ * offset + 5 (8 bit): data
+ *
+ * Read the register given by "I2C register" on the device addressed
+ * by "I2C slave address" on the I2C bus given by "DCB I2C table
+ * entry index". Compare the result AND "mask" to "data".
+ * If they're not equal, skip subsequent opcodes until condition is
+ * inverted (INIT_NOT), or we hit INIT_RESUME
+ */
+
+ uint8_t i2c_index = bios->data[offset + 1];
+ uint8_t i2c_address = bios->data[offset + 2] >> 1;
+ uint8_t reg = bios->data[offset + 3];
+ uint8_t mask = bios->data[offset + 4];
+ uint8_t data = bios->data[offset + 5];
+ struct nouveau_i2c_chan *chan;
+ union i2c_smbus_data val;
+ int ret;
+
+ /* no execute check by design */
+
+ BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
+ offset, i2c_index, i2c_address);
+
+ chan = init_i2c_device_find(bios->dev, i2c_index);
+ if (!chan)
+ return -ENODEV;
+
+ ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
+ I2C_SMBUS_READ, reg,
+ I2C_SMBUS_BYTE_DATA, &val);
+ if (ret < 0) {
+ BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: [no device], "
+ "Mask: 0x%02X, Data: 0x%02X\n",
+ offset, reg, mask, data);
+ iexec->execute = 0;
+ return 6;
+ }
+
+ BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
+ "Mask: 0x%02X, Data: 0x%02X\n",
+ offset, reg, val.byte, mask, data);
+
+ iexec->execute = ((val.byte & mask) == data);
+
+ return 6;
+}
+
+static int
init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
@@ -2039,6 +2152,325 @@ 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)) {
+ uint8_t __iomem *p =
+ io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
+
+ val = ioread32(p + (off & ~PAGE_MASK));
+
+ io_mapping_unmap_atomic(p, KM_USER0);
+ }
+
+ 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)) {
+ uint8_t __iomem *p =
+ io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
+
+ iowrite32(val, p + (off & ~PAGE_MASK));
+ wmb();
+
+ io_mapping_unmap_atomic(p, KM_USER0);
+ }
+}
+
+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 +2479,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 +2556,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 +2593,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 +2606,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 +2648,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);
@@ -2252,10 +2678,10 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset,
/* no iexec->execute check by design */
uint32_t straps = bios_rd32(bios, NV_PEXTDEV_BOOT_0);
- uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6));
+ uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & 0x40) >> 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 +2815,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 +2827,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 +3221,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) {
+ 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 +3242,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 +3299,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 +3307,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 +3491,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 +3511,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 +3520,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 +3550,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,13 +3568,76 @@ 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;
}
}
return len;
}
+static int
+init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+ /*
+ * INIT_I2C_LONG_IF opcode: 0x9A ('')
+ *
+ * offset (8 bit): opcode
+ * offset + 1 (8 bit): DCB I2C table entry index
+ * offset + 2 (8 bit): I2C slave address
+ * offset + 3 (16 bit): I2C register
+ * offset + 5 (8 bit): mask
+ * offset + 6 (8 bit): data
+ *
+ * Read the register given by "I2C register" on the device addressed
+ * by "I2C slave address" on the I2C bus given by "DCB I2C table
+ * entry index". Compare the result AND "mask" to "data".
+ * If they're not equal, skip subsequent opcodes until condition is
+ * inverted (INIT_NOT), or we hit INIT_RESUME
+ */
+
+ uint8_t i2c_index = bios->data[offset + 1];
+ uint8_t i2c_address = bios->data[offset + 2] >> 1;
+ uint8_t reglo = bios->data[offset + 3];
+ uint8_t reghi = bios->data[offset + 4];
+ uint8_t mask = bios->data[offset + 5];
+ uint8_t data = bios->data[offset + 6];
+ struct nouveau_i2c_chan *chan;
+ uint8_t buf0[2] = { reghi, reglo };
+ uint8_t buf1[1];
+ struct i2c_msg msg[2] = {
+ { i2c_address, 0, 1, buf0 },
+ { i2c_address, I2C_M_RD, 1, buf1 },
+ };
+ int ret;
+
+ /* no execute check by design */
+
+ BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
+ offset, i2c_index, i2c_address);
+
+ chan = init_i2c_device_find(bios->dev, i2c_index);
+ if (!chan)
+ return -ENODEV;
+
+
+ ret = i2c_transfer(&chan->adapter, msg, 2);
+ if (ret < 0) {
+ BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], "
+ "Mask: 0x%02X, Data: 0x%02X\n",
+ offset, reghi, reglo, mask, data);
+ iexec->execute = 0;
+ return 7;
+ }
+
+ BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: 0x%02X, "
+ "Mask: 0x%02X, Data: 0x%02X\n",
+ offset, reghi, reglo, buf1[0], mask, data);
+
+ iexec->execute = ((buf1[0] & mask) == data);
+
+ return 7;
+}
+
static struct init_tbl_entry itbl_entry[] = {
/* command name , id , length , offset , mult , command handler */
/* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */
@@ -3174,9 +3664,11 @@ static struct init_tbl_entry itbl_entry[] = {
{ "INIT_ZM_CR" , 0x53, init_zm_cr },
{ "INIT_ZM_CR_GROUP" , 0x54, init_zm_cr_group },
{ "INIT_CONDITION_TIME" , 0x56, init_condition_time },
+ { "INIT_LTIME" , 0x57, init_ltime },
{ "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence },
/* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
{ "INIT_SUB_DIRECT" , 0x5B, init_sub_direct },
+ { "INIT_I2C_IF" , 0x5E, init_i2c_if },
{ "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg },
{ "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io },
{ "INIT_COMPUTE_MEM" , 0x63, init_compute_mem },
@@ -3210,6 +3702,7 @@ static struct init_tbl_entry itbl_entry[] = {
{ "INIT_97" , 0x97, init_97 },
{ "INIT_AUXCH" , 0x98, init_auxch },
{ "INIT_ZM_AUXCH" , 0x99, init_zm_auxch },
+ { "INIT_I2C_LONG_IF" , 0x9A, init_i2c_long_if },
{ NULL , 0 , NULL }
};
@@ -3376,27 +3869,10 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entr
}
#ifdef __powerpc__
/* Powerbook specific quirks */
- if ((dev->pci_device & 0xffff) == 0x0179 ||
- (dev->pci_device & 0xffff) == 0x0189 ||
- (dev->pci_device & 0xffff) == 0x0329) {
- if (script == LVDS_RESET) {
- nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72);
-
- } else if (script == LVDS_PANEL_ON) {
- bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL,
- bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL)
- | (1 << 31));
- bios_wr32(bios, NV_PCRTC_GPIO_EXT,
- bios_rd32(bios, NV_PCRTC_GPIO_EXT) | 1);
-
- } else if (script == LVDS_PANEL_OFF) {
- bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL,
- bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL)
- & ~(1 << 31));
- bios_wr32(bios, NV_PCRTC_GPIO_EXT,
- bios_rd32(bios, NV_PCRTC_GPIO_EXT) & ~3);
- }
- }
+ if (script == LVDS_RESET &&
+ (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 ||
+ dev->pci_device == 0x0329))
+ nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72);
#endif
return 0;
@@ -3888,11 +4364,8 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
*
* For the moment, a quirk will do :)
*/
- if ((dev->pdev->device == 0x01d7) &&
- (dev->pdev->subsystem_vendor == 0x1028) &&
- (dev->pdev->subsystem_device == 0x01c2)) {
+ if (nv_match_device(dev, 0x01d7, 0x1028, 0x01c2))
bios->fp.duallink_transition_clk = 80000;
- }
/* set dual_link flag for EDID case */
if (pxclk && (chip_version < 0x25 || chip_version > 0x28))
@@ -4068,7 +4541,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
bios->display.script_table_ptr,
table[2], table[3], table[0] >= 0x21);
if (!otable) {
- NV_ERROR(dev, "Couldn't find matching output script table\n");
+ NV_DEBUG_KMS(dev, "failed to match any output table\n");
return 1;
}
@@ -4094,7 +4567,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
return 1;
}
- NV_TRACE(dev, "0x%04X: parsing output script 0\n", script);
+ NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script);
nouveau_bios_run_init_table(dev, script, dcbent);
} else
if (pxclk == -1) {
@@ -4104,7 +4577,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
return 1;
}
- NV_TRACE(dev, "0x%04X: parsing output script 1\n", script);
+ NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script);
nouveau_bios_run_init_table(dev, script, dcbent);
} else
if (pxclk == -2) {
@@ -4117,7 +4590,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
return 1;
}
- NV_TRACE(dev, "0x%04X: parsing output script 2\n", script);
+ NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script);
nouveau_bios_run_init_table(dev, script, dcbent);
} else
if (pxclk > 0) {
@@ -4125,11 +4598,11 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
if (script)
script = clkcmptable(bios, script, pxclk);
if (!script) {
- NV_ERROR(dev, "clock script 0 not found\n");
+ NV_DEBUG_KMS(dev, "clock script 0 not found\n");
return 1;
}
- NV_TRACE(dev, "0x%04X: parsing clock script 0\n", script);
+ NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script);
nouveau_bios_run_init_table(dev, script, dcbent);
} else
if (pxclk < 0) {
@@ -4141,7 +4614,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
return 1;
}
- NV_TRACE(dev, "0x%04X: parsing clock script 1\n", script);
+ NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script);
nouveau_bios_run_init_table(dev, script, dcbent);
}
@@ -4484,7 +4957,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
pll_lim->min_p = record[12];
pll_lim->max_p = record[13];
/* where did this go to?? */
- if (limit_match == 0x00614100 || limit_match == 0x00614900)
+ if ((entry[0] & 0xf0) == 0x80)
pll_lim->refclk = 27000;
else
pll_lim->refclk = 100000;
@@ -4864,19 +5337,17 @@ static int parse_bit_tmds_tbl_entry(struct drm_device *dev, struct nvbios *bios,
}
tmdstableptr = ROM16(bios->data[bitentry->offset]);
-
- if (tmdstableptr == 0x0) {
+ if (!tmdstableptr) {
NV_ERROR(dev, "Pointer to TMDS table invalid\n");
return -EINVAL;
}
+ NV_INFO(dev, "TMDS table version %d.%d\n",
+ bios->data[tmdstableptr] >> 4, bios->data[tmdstableptr] & 0xf);
+
/* nv50+ has v2.0, but we don't parse it atm */
- if (bios->data[tmdstableptr] != 0x11) {
- NV_WARN(dev,
- "TMDS table revision %d.%d not currently supported\n",
- bios->data[tmdstableptr] >> 4, bios->data[tmdstableptr] & 0xf);
+ if (bios->data[tmdstableptr] != 0x11)
return -ENOSYS;
- }
/*
* These two scripts are odd: they don't seem to get run even when
@@ -5151,10 +5622,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]);
@@ -5312,6 +5787,20 @@ parse_dcb_gpio_table(struct nvbios *bios)
gpio->line = tvdac_gpio[1] >> 4;
gpio->invert = tvdac_gpio[0] & 2;
}
+ } else {
+ /*
+ * No systematic way to store GPIO info on pre-v2.2
+ * DCBs, try to match the PCI device IDs.
+ */
+
+ /* Apple iMac G4 NV18 */
+ if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) {
+ struct dcb_gpio_entry *gpio = new_gpio_entry(bios);
+
+ gpio->tag = DCB_GPIO_TVDAC0;
+ gpio->line = 4;
+ }
+
}
if (!gpio_table_ptr)
@@ -5387,9 +5876,7 @@ apply_dcb_connector_quirks(struct nvbios *bios, int idx)
struct drm_device *dev = bios->dev;
/* Gigabyte NX85T */
- if ((dev->pdev->device == 0x0421) &&
- (dev->pdev->subsystem_vendor == 0x1458) &&
- (dev->pdev->subsystem_device == 0x344c)) {
+ if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) {
if (cte->type == DCB_CONNECTOR_HDMI_1)
cte->type = DCB_CONNECTOR_DVI_I;
}
@@ -5506,7 +5993,7 @@ static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads)
entry->i2c_index = i2c;
entry->heads = heads;
entry->location = DCB_LOC_ON_CHIP;
- /* "or" mostly unused in early gen crt modesetting, 0 is fine */
+ entry->or = 1;
}
static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads)
@@ -5589,9 +6076,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) {
/*
@@ -5631,9 +6121,15 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
}
break;
case OUTPUT_TMDS:
- entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
+ if (dcb->version >= 0x40)
+ entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
+ else if (dcb->version >= 0x30)
+ entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8;
+ else if (dcb->version >= 0x22)
+ entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4;
+
break;
- case 0xe:
+ case OUTPUT_EOL:
/* weird g80 mobile type that "nv" treats as a terminator */
dcb->entries--;
return false;
@@ -5670,22 +6166,14 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb,
entry->type = OUTPUT_TV;
break;
case 2:
- case 3:
- entry->type = OUTPUT_LVDS;
- break;
case 4:
- switch ((conn & 0x000000f0) >> 4) {
- case 0:
- entry->type = OUTPUT_TMDS;
- break;
- case 1:
+ if (conn & 0x10)
entry->type = OUTPUT_LVDS;
- break;
- default:
- NV_ERROR(dev, "Unknown DCB subtype 4/%d\n",
- (conn & 0x000000f0) >> 4);
- return false;
- }
+ else
+ entry->type = OUTPUT_TMDS;
+ break;
+ case 3:
+ entry->type = OUTPUT_LVDS;
break;
default:
NV_ERROR(dev, "Unknown DCB type %d\n", conn & 0x0000000f);
@@ -5706,13 +6194,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 +6274,29 @@ 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 (nv_match_device(dev, 0x040d, 0x1028, 0x019b)) {
+ if (*conn == 0x02026312 && *conf == 0x00000020)
+ return false;
+ }
+
+ return true;
+}
+
static int
parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
{
@@ -5903,6 +6407,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
dcb->i2c_table = &bios->data[i2ctabptr];
if (dcb->version >= 0x30)
dcb->i2c_default_indices = dcb->i2c_table[4];
+
+ /*
+ * Parse the "management" I2C bus, used for hardware
+ * monitoring and some external TMDS transmitters.
+ */
+ if (dcb->version >= 0x22) {
+ int idx = (dcb->version >= 0x40 ?
+ dcb->i2c_default_indices & 0xf :
+ 2);
+
+ read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
+ idx, &dcb->i2c[idx]);
+ }
}
if (entries > DCB_MAX_NUM_ENTRIES)
@@ -5926,6 +6443,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 +6701,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 +6735,6 @@ nouveau_run_vbios_init(struct drm_device *dev)
}
}
- NVLockVgaCrtcs(dev, true);
-
return ret;
}
@@ -6238,7 +6755,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 +6764,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 +6778,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 +6797,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;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index adf4ec2d06c..c1de2f3fcb0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -81,6 +81,7 @@ struct dcb_connector_table_entry {
enum dcb_connector_type type;
uint8_t index2;
uint8_t gpio_tag;
+ void *drm;
};
struct dcb_connector_table {
@@ -94,6 +95,7 @@ enum dcb_type {
OUTPUT_TMDS = 2,
OUTPUT_LVDS = 3,
OUTPUT_DP = 6,
+ OUTPUT_EOL = 14, /* DCB 4.0+, appears to be end-of-list */
OUTPUT_ANY = -1
};
@@ -117,6 +119,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 {
@@ -129,6 +132,7 @@ struct dcb_entry {
} dpconf;
struct {
struct sor_conf sor;
+ int slave_addr;
} tmdsconf;
};
bool i2c_upper_default;
@@ -249,8 +253,6 @@ struct nvbios {
struct {
int crtchead;
- /* these need remembering across suspend */
- uint32_t saved_nv_pfb_cfg0;
} state;
struct {
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 6f3c1952237..f6f44779d82 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -36,6 +36,21 @@
#include <linux/log2.h>
#include <linux/slab.h>
+int
+nouveau_bo_sync_gpu(struct nouveau_bo *nvbo, struct nouveau_channel *chan)
+{
+ struct nouveau_fence *prev_fence = nvbo->bo.sync_obj;
+ int ret;
+
+ if (!prev_fence || nouveau_fence_channel(prev_fence) == chan)
+ return 0;
+
+ spin_lock(&nvbo->bo.lock);
+ ret = ttm_bo_wait(&nvbo->bo, false, false, false);
+ spin_unlock(&nvbo->bo.lock);
+ return ret;
+}
+
static void
nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
{
@@ -51,9 +66,6 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
if (nvbo->tile)
nv10_mem_expire_tiling(dev, nvbo->tile, NULL);
- spin_lock(&dev_priv->ttm.bo_list_lock);
- list_del(&nvbo->head);
- spin_unlock(&dev_priv->ttm.bo_list_lock);
kfree(nvbo);
}
@@ -166,9 +178,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
}
nvbo->channel = NULL;
- spin_lock(&dev_priv->ttm.bo_list_lock);
- list_add_tail(&nvbo->head, &dev_priv->ttm.bo_list);
- spin_unlock(&dev_priv->ttm.bo_list_lock);
*pnvbo = nvbo;
return 0;
}
@@ -461,9 +470,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 +720,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;
}
@@ -783,7 +791,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
break;
case TTM_PL_VRAM:
mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
- mem->bus.base = drm_get_resource_start(dev, 1);
+ mem->bus.base = pci_resource_start(dev->pdev, 1);
mem->bus.is_iomem = true;
break;
default:
diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c
index 88f9bc0941e..ca85da78484 100644
--- a/drivers/gpu/drm/nouveau/nouveau_calc.c
+++ b/drivers/gpu/drm/nouveau/nouveau_calc.c
@@ -200,7 +200,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
struct nv_sim_state sim_data;
int MClk = nouveau_hw_get_clock(dev, MPLL);
int NVClk = nouveau_hw_get_clock(dev, NVPLL);
- uint32_t cfg1 = nvReadFB(dev, NV_PFB_CFG1);
+ uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1);
sim_data.pclk_khz = VClk;
sim_data.mclk_khz = MClk;
@@ -218,7 +218,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
sim_data.mem_latency = 3;
sim_data.mem_page_miss = 10;
} else {
- sim_data.memory_type = nvReadFB(dev, NV_PFB_CFG0) & 0x1;
+ sim_data.memory_type = nvReadFB(dev, NV04_PFB_CFG0) & 0x1;
sim_data.memory_width = (nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64;
sim_data.mem_latency = cfg1 & 0xf;
sim_data.mem_page_miss = ((cfg1 >> 4) & 0xf) + ((cfg1 >> 31) & 0x1);
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 1fc57ef5829..0480f064f2c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -62,7 +62,8 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
* VRAM.
*/
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
- drm_get_resource_start(dev, 1),
+ pci_resource_start(dev->pdev,
+ 1),
dev_priv->fb_available_size,
NV_DMA_ACCESS_RO,
NV_DMA_TARGET_PCI, &pushbuf);
@@ -257,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;
@@ -368,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;
@@ -418,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);
@@ -430,18 +426,18 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
***********************************/
struct drm_ioctl_desc nouveau_ioctls[] = {
- DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH),
};
int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 149ed224c3c..a1473fff06a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -37,12 +37,6 @@
#include "nouveau_connector.h"
#include "nouveau_hw.h"
-static inline struct drm_encoder_slave_funcs *
-get_slave_funcs(struct nouveau_encoder *enc)
-{
- return to_encoder_slave(to_drm_encoder(enc))->slave_funcs;
-}
-
static struct nouveau_encoder *
find_encoder_by_type(struct drm_connector *connector, int type)
{
@@ -102,60 +96,12 @@ 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;
@@ -174,14 +120,8 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
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 +174,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 +185,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 +245,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)
{
@@ -353,6 +356,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
{
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
+ struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
struct drm_device *dev = connector->dev;
int ret;
@@ -425,8 +429,8 @@ nouveau_connector_set_property(struct drm_connector *connector,
}
if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)
- return get_slave_funcs(nv_encoder)->
- set_property(to_drm_encoder(nv_encoder), connector, property, value);
+ return get_slave_funcs(encoder)->set_property(
+ encoder, connector, property, value);
return -EINVAL;
}
@@ -441,7 +445,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 +539,28 @@ 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;
+ struct drm_encoder *encoder = to_drm_encoder(nv_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
@@ -566,10 +578,10 @@ nouveau_connector_get_modes(struct drm_connector *connector)
}
if (nv_encoder->dcb->type == OUTPUT_TV)
- ret = get_slave_funcs(nv_encoder)->
- get_modes(to_drm_encoder(nv_encoder), connector);
+ ret = get_slave_funcs(encoder)->get_modes(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;
@@ -582,6 +594,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
+ struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
unsigned min_clock = 25000, max_clock = min_clock;
unsigned clock = mode->clock;
@@ -608,8 +621,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
max_clock = 350000;
break;
case OUTPUT_TV:
- return get_slave_funcs(nv_encoder)->
- mode_valid(to_drm_encoder(nv_encoder), mode);
+ return get_slave_funcs(encoder)->mode_valid(encoder, mode);
case OUTPUT_DP:
if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7)
max_clock = nv_encoder->dp.link_nr * 270000;
@@ -643,6 +655,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 +712,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 +787,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 +811,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 +824,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 +837,15 @@ nouveau_connector_create(struct drm_device *dev,
break;
}
+ nouveau_connector_set_polling(connector);
+
drm_sysfs_connector_add(connector);
+ dcb->drm = connector;
+ return dcb->drm;
- if (dcb->type == DCB_CONNECTOR_LVDS) {
- ret = nouveau_connector_create_lvds(dev, connector);
- if (ret) {
- connector->funcs->destroy(connector);
- return ret;
- }
- }
+fail:
+ drm_connector_cleanup(connector);
+ kfree(connector);
+ return ERR_PTR(ret);
- return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index 4ef38abc2d9..0d2e668ccfe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -49,7 +49,10 @@ static inline struct nouveau_connector *nouveau_connector(
return container_of(con, struct nouveau_connector, base);
}
-int nouveau_connector_create(struct drm_device *,
- struct dcb_connector_table_entry *);
+struct drm_connector *
+nouveau_connector_create(struct drm_device *, int index);
+
+void
+nouveau_connector_set_polling(struct drm_connector *);
#endif /* __NOUVEAU_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 74e6b4ed12c..2e11fd65b4d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -84,16 +84,16 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
if (!gem)
- return NULL;
+ return ERR_PTR(-ENOENT);
nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
if (!nouveau_fb)
- return NULL;
+ return ERR_PTR(-ENOMEM);
ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
if (ret) {
drm_gem_object_unreference(gem);
- return NULL;
+ return ERR_PTR(ret);
}
return &nouveau_fb->base;
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index 65c441a1999..2e3c6caa97e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -92,11 +92,9 @@ nouveau_dma_init(struct nouveau_channel *chan)
return ret;
/* Map M2MF notifier object - fbcon. */
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- ret = nouveau_bo_map(chan->notifier_bo);
- if (ret)
- return ret;
- }
+ ret = nouveau_bo_map(chan->notifier_bo);
+ if (ret)
+ return ret;
/* Insert NOPS for NOUVEAU_DMA_SKIPS */
ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index deeb21c6865..8a1b188b4cd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -23,8 +23,10 @@
*/
#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;
}
@@ -535,47 +572,64 @@ out:
return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY);
}
-int
-nouveau_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
- uint8_t write_byte, uint8_t *read_byte)
+static int
+nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
- struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
- struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adapter;
+ struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap;
struct drm_device *dev = auxch->dev;
- int ret = 0, cmd, addr = algo_data->address;
- uint8_t *buf;
-
- if (mode == MODE_I2C_READ) {
- cmd = AUX_I2C_READ;
- buf = read_byte;
- } else {
- cmd = (mode & MODE_I2C_READ) ? AUX_I2C_READ : AUX_I2C_WRITE;
- buf = &write_byte;
- }
+ struct i2c_msg *msg = msgs;
+ int ret, mcnt = num;
- if (!(mode & MODE_I2C_STOP))
- cmd |= AUX_I2C_MOT;
+ while (mcnt--) {
+ u8 remaining = msg->len;
+ u8 *ptr = msg->buf;
- if (mode & MODE_I2C_START)
- return 1;
+ while (remaining) {
+ u8 cnt = (remaining > 16) ? 16 : remaining;
+ u8 cmd;
- for (;;) {
- ret = nouveau_dp_auxch(auxch, cmd, addr, buf, 1);
- if (ret < 0)
- return ret;
-
- switch (ret & NV50_AUXCH_STAT_REPLY_I2C) {
- case NV50_AUXCH_STAT_REPLY_I2C_ACK:
- return 1;
- case NV50_AUXCH_STAT_REPLY_I2C_NACK:
- return -EREMOTEIO;
- case NV50_AUXCH_STAT_REPLY_I2C_DEFER:
- udelay(100);
- break;
- default:
- NV_ERROR(dev, "invalid auxch status: 0x%08x\n", ret);
- return -EREMOTEIO;
+ if (msg->flags & I2C_M_RD)
+ cmd = AUX_I2C_READ;
+ else
+ cmd = AUX_I2C_WRITE;
+
+ if (mcnt || remaining > 16)
+ cmd |= AUX_I2C_MOT;
+
+ ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt);
+ if (ret < 0)
+ return ret;
+
+ switch (ret & NV50_AUXCH_STAT_REPLY_I2C) {
+ case NV50_AUXCH_STAT_REPLY_I2C_ACK:
+ break;
+ case NV50_AUXCH_STAT_REPLY_I2C_NACK:
+ return -EREMOTEIO;
+ case NV50_AUXCH_STAT_REPLY_I2C_DEFER:
+ udelay(100);
+ continue;
+ default:
+ NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret);
+ return -EREMOTEIO;
+ }
+
+ ptr += cnt;
+ remaining -= cnt;
}
+
+ msg++;
}
+
+ return num;
+}
+
+static u32
+nouveau_dp_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
+const struct i2c_algorithm nouveau_dp_i2c_algo = {
+ .master_xfer = nouveau_dp_i2c_xfer,
+ .functionality = nouveau_dp_i2c_func
+};
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 27377043229..1de5eb53e01 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -35,10 +35,6 @@
#include "drm_pciids.h"
-MODULE_PARM_DESC(ctxfw, "Use external firmware blob for grctx init (NV40)");
-int nouveau_ctxfw = 0;
-module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
-
MODULE_PARM_DESC(noagp, "Disable AGP");
int nouveau_noagp;
module_param_named(noagp, nouveau_noagp, int, 0400);
@@ -56,7 +52,7 @@ int nouveau_vram_pushbuf;
module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM");
-int nouveau_vram_notify = 1;
+int nouveau_vram_notify = 0;
module_param_named(vram_notify, nouveau_vram_notify, int, 0400);
MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)");
@@ -132,7 +128,7 @@ static struct drm_driver driver;
static int __devinit
nouveau_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- return drm_get_dev(pdev, ent, &driver);
+ return drm_get_pci_dev(pdev, ent, &driver);
}
static void
@@ -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();
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index c6971910648..b1be617373b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo)
return ioptr;
}
-struct mem_block {
- struct mem_block *next;
- struct mem_block *prev;
- uint64_t start;
- uint64_t size;
- struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
-};
-
enum nouveau_flags {
NV_NFORCE = 0x10000000,
NV_NFORCE2 = 0x20000000
@@ -149,7 +141,7 @@ struct nouveau_gpuobj {
struct list_head list;
struct nouveau_channel *im_channel;
- struct mem_block *im_pramin;
+ struct drm_mm_node *im_pramin;
struct nouveau_bo *im_backing;
uint32_t im_backing_start;
uint32_t *im_backing_suspend;
@@ -196,7 +188,7 @@ struct nouveau_channel {
struct list_head pending;
uint32_t sequence;
uint32_t sequence_ack;
- uint32_t last_sequence_irq;
+ atomic_t last_sequence_irq;
} fence;
/* DMA push buffer */
@@ -206,7 +198,7 @@ struct nouveau_channel {
/* Notifier memory */
struct nouveau_bo *notifier_bo;
- struct mem_block *notifier_heap;
+ struct drm_mm notifier_heap;
/* PFIFO context */
struct nouveau_gpuobj_ref *ramfc;
@@ -224,7 +216,7 @@ struct nouveau_channel {
/* Objects */
struct nouveau_gpuobj_ref *ramin; /* Private instmem */
- struct mem_block *ramin_heap; /* Private PRAMIN heap */
+ struct drm_mm ramin_heap; /* Private PRAMIN heap */
struct nouveau_gpuobj_ref *ramht; /* Hash table */
struct list_head ramht_refs; /* Objects referenced by RAMHT */
@@ -277,8 +269,7 @@ struct nouveau_instmem_engine {
void (*clear)(struct drm_device *, struct nouveau_gpuobj *);
int (*bind)(struct drm_device *, struct nouveau_gpuobj *);
int (*unbind)(struct drm_device *, struct nouveau_gpuobj *);
- void (*prepare_access)(struct drm_device *, bool write);
- void (*finish_access)(struct drm_device *);
+ void (*flush)(struct drm_device *);
};
struct nouveau_mc_engine {
@@ -303,10 +294,11 @@ struct nouveau_fb_engine {
};
struct nouveau_fifo_engine {
- void *priv;
-
int channels;
+ struct nouveau_gpuobj_ref *playlist[2];
+ int cur_playlist;
+
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
@@ -339,10 +331,11 @@ struct nouveau_pgraph_object_class {
struct nouveau_pgraph_engine {
struct nouveau_pgraph_object_class *grclass;
bool accel_blocked;
- void *ctxprog;
- void *ctxvals;
int grctx_size;
+ /* NV2x/NV3x context table (0x400780) */
+ struct nouveau_gpuobj_ref *ctx_table;
+
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
@@ -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 {
@@ -397,7 +410,7 @@ enum nv04_fp_display_regs {
struct nv04_crtc_reg {
unsigned char MiscOutReg; /* */
- uint8_t CRTC[0x9f];
+ uint8_t CRTC[0xa0];
uint8_t CR58[0x10];
uint8_t Sequencer[5];
uint8_t Graphics[9];
@@ -496,15 +509,11 @@ enum nouveau_card_type {
NV_30 = 0x30,
NV_40 = 0x40,
NV_50 = 0x50,
+ NV_C0 = 0xc0,
};
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;
@@ -525,16 +534,12 @@ struct drm_nouveau_private {
struct list_head vbl_waiting;
struct {
- struct ttm_global_reference mem_global_ref;
+ struct drm_global_reference mem_global_ref;
struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
- spinlock_t bo_list_lock;
- struct list_head bo_list;
atomic_t validate_sequence;
} ttm;
- struct fb_info *fbdev_info;
-
int fifo_alloc_count;
struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
@@ -595,11 +600,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 +619,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 +658,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 +680,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 +704,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 +847,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 +916,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 *);
@@ -934,6 +930,10 @@ extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
extern int nv50_fb_init(struct drm_device *);
extern void nv50_fb_takedown(struct drm_device *);
+/* nvc0_fb.c */
+extern int nvc0_fb_init(struct drm_device *);
+extern void nvc0_fb_takedown(struct drm_device *);
+
/* nv04_fifo.c */
extern int nv04_fifo_init(struct drm_device *);
extern void nv04_fifo_disable(struct drm_device *);
@@ -971,6 +971,20 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *);
extern int nv50_fifo_load_context(struct nouveau_channel *);
extern int nv50_fifo_unload_context(struct drm_device *);
+/* nvc0_fifo.c */
+extern int nvc0_fifo_init(struct drm_device *);
+extern void nvc0_fifo_takedown(struct drm_device *);
+extern void nvc0_fifo_disable(struct drm_device *);
+extern void nvc0_fifo_enable(struct drm_device *);
+extern bool nvc0_fifo_reassign(struct drm_device *, bool);
+extern bool nvc0_fifo_cache_flush(struct drm_device *);
+extern bool nvc0_fifo_cache_pull(struct drm_device *, bool);
+extern int nvc0_fifo_channel_id(struct drm_device *);
+extern int nvc0_fifo_create_context(struct nouveau_channel *);
+extern void nvc0_fifo_destroy_context(struct nouveau_channel *);
+extern int nvc0_fifo_load_context(struct nouveau_channel *);
+extern int nvc0_fifo_unload_context(struct drm_device *);
+
/* nv04_graph.c */
extern struct nouveau_pgraph_object_class nv04_graph_grclass[];
extern int nv04_graph_init(struct drm_device *);
@@ -1035,11 +1049,15 @@ 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 *);
+/* nvc0_graph.c */
+extern int nvc0_graph_init(struct drm_device *);
+extern void nvc0_graph_takedown(struct drm_device *);
+extern void nvc0_graph_fifo_access(struct drm_device *, bool);
+extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *);
+extern int nvc0_graph_create_context(struct nouveau_channel *);
+extern void nvc0_graph_destroy_context(struct nouveau_channel *);
+extern int nvc0_graph_load_context(struct nouveau_channel *);
+extern int nvc0_graph_unload_context(struct drm_device *);
/* nv04_instmem.c */
extern int nv04_instmem_init(struct drm_device *);
@@ -1051,8 +1069,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 +1081,21 @@ 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);
+
+/* nvc0_instmem.c */
+extern int nvc0_instmem_init(struct drm_device *);
+extern void nvc0_instmem_takedown(struct drm_device *);
+extern int nvc0_instmem_suspend(struct drm_device *);
+extern void nvc0_instmem_resume(struct drm_device *);
+extern int nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
+ uint32_t *size);
+extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
+extern int nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
+extern int nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
+extern void nvc0_instmem_flush(struct drm_device *);
/* nv04_mc.c */
extern int nv04_mc_init(struct drm_device *);
@@ -1088,13 +1118,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 +1134,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);
@@ -1132,6 +1165,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index);
extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val);
+extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
/* nouveau_fence.c */
struct nouveau_fence;
@@ -1147,7 +1181,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 +1200,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 +1255,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;
@@ -1346,6 +1389,15 @@ nv_two_reg_pll(struct drm_device *dev)
return false;
}
+static inline bool
+nv_match_device(struct drm_device *dev, unsigned device,
+ unsigned sub_vendor, unsigned sub_device)
+{
+ return dev->pdev->device == device &&
+ dev->pdev->subsystem_vendor == sub_vendor &&
+ dev->pdev->subsystem_device == sub_device;
+}
+
#define NV_SW 0x0000506e
#define NV_SW_DMA_SEMAPHORE 0x00000060
#define NV_SW_SEMAPHORE_OFFSET 0x00000064
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index e1df8209cd0..7c82d68bc15 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -38,13 +38,15 @@ struct nouveau_encoder {
struct dcb_entry *dcb;
int or;
+ /* different to drm_encoder.crtc, this reflects what's
+ * actually programmed on the hw, not the proposed crtc */
+ struct drm_crtc *crtc;
+
struct drm_display_mode mode;
int last_dpms;
struct nv04_output_reg restore;
- void (*disconnect)(struct nouveau_encoder *encoder);
-
union {
struct {
int mc_unknown;
@@ -69,10 +71,16 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
return &enc->base.base;
}
+static inline struct drm_encoder_slave_funcs *
+get_slave_funcs(struct drm_encoder *enc)
+{
+ return to_encoder_slave(enc)->slave_funcs;
+}
+
struct nouveau_connector *
nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
-int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry);
-int nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry);
+int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
+int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
struct bit_displayport_encoder_table {
uint32_t match;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 257ea130ae1..dbd30b2e43f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -250,6 +250,7 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT;
+ info->flags |= FBINFO_CAN_FORCE_OUTPUT;
info->fbops = &nouveau_fbcon_ops;
info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset -
dev_priv->vm_vram_base;
@@ -280,6 +281,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
if (dev_priv->channel && !nouveau_nofbaccel) {
switch (dev_priv->card_type) {
+ case NV_C0:
+ break;
case NV_50:
nv50_fbcon_accel_init(info);
info->fbops = &nv50_fbcon_ops;
@@ -333,7 +336,7 @@ nouveau_fbcon_output_poll_changed(struct drm_device *dev)
drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper);
}
-int
+static int
nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
{
struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index faddf53ff9e..87ac21ec23d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -64,13 +64,15 @@ nouveau_fence_update(struct nouveau_channel *chan)
struct nouveau_fence *fence;
uint32_t sequence;
+ spin_lock(&chan->fence.lock);
+
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;
+ goto out;
chan->fence.sequence_ack = sequence;
list_for_each_safe(entry, tmp, &chan->fence.pending) {
@@ -84,6 +86,8 @@ nouveau_fence_update(struct nouveau_channel *chan)
if (sequence == chan->fence.sequence_ack)
break;
}
+out:
+ spin_unlock(&chan->fence.lock);
}
int
@@ -119,7 +123,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 +130,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 +139,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 +174,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 +188,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 +197,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 +219,12 @@ nouveau_fence_flush(void *sync_obj, void *sync_arg)
return 0;
}
-void
-nouveau_fence_handler(struct drm_device *dev, int channel)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan = NULL;
-
- if (channel >= 0 && channel < dev_priv->engine.fifo.channels)
- chan = dev_priv->fifos[channel];
-
- if (chan) {
- spin_lock_irq(&chan->fence.lock);
- nouveau_fence_update(chan);
- spin_unlock_irq(&chan->fence.lock);
- }
-}
-
int
nouveau_fence_init(struct nouveau_channel *chan)
{
INIT_LIST_HEAD(&chan->fence.pending);
spin_lock_init(&chan->fence.lock);
+ atomic_set(&chan->fence.last_sequence_irq, 0);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 69c76cf9340..ead7b8fc53f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -137,8 +137,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
uint32_t flags = 0;
int ret = 0;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL))
dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping;
@@ -247,7 +245,7 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
list_del(&nvbo->entry);
nvbo->reserved_by = NULL;
ttm_bo_unreserve(&nvbo->bo);
- drm_gem_object_unreference(nvbo->gem);
+ drm_gem_object_unreference_unlocked(nvbo->gem);
}
}
@@ -286,7 +284,7 @@ retry:
if (!gem) {
NV_ERROR(dev, "Unknown handle 0x%08x\n", b->handle);
validate_fini(op, NULL);
- return -EINVAL;
+ return -ENOENT;
}
nvbo = gem->driver_private;
@@ -302,7 +300,7 @@ retry:
validate_fini(op, NULL);
if (ret == -EAGAIN)
ret = ttm_bo_wait_unreserved(&nvbo->bo, false);
- drm_gem_object_unreference(gem);
+ drm_gem_object_unreference_unlocked(gem);
if (ret) {
NV_ERROR(dev, "fail reserve\n");
return ret;
@@ -339,7 +337,9 @@ retry:
return -EINVAL;
}
+ mutex_unlock(&drm_global_mutex);
ret = ttm_bo_wait_cpu(&nvbo->bo, false);
+ mutex_lock(&drm_global_mutex);
if (ret) {
NV_ERROR(dev, "fail wait_cpu\n");
return ret;
@@ -363,16 +363,11 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
list_for_each_entry(nvbo, list, entry) {
struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
- struct nouveau_fence *prev_fence = nvbo->bo.sync_obj;
- if (prev_fence && nouveau_fence_channel(prev_fence) != chan) {
- spin_lock(&nvbo->bo.lock);
- ret = ttm_bo_wait(&nvbo->bo, false, false, false);
- spin_unlock(&nvbo->bo.lock);
- if (unlikely(ret)) {
- NV_ERROR(dev, "fail wait other chan\n");
- return ret;
- }
+ ret = nouveau_bo_sync_gpu(nvbo, chan);
+ if (unlikely(ret)) {
+ NV_ERROR(dev, "fail pre-validate sync\n");
+ return ret;
}
ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains,
@@ -383,7 +378,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
return ret;
}
- nvbo->channel = chan;
+ nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan;
ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement,
false, false, false);
nvbo->channel = NULL;
@@ -392,6 +387,12 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
return ret;
}
+ ret = nouveau_bo_sync_gpu(nvbo, chan);
+ if (unlikely(ret)) {
+ NV_ERROR(dev, "fail post-validate sync\n");
+ return ret;
+ }
+
if (nvbo->bo.offset == b->presumed.offset &&
((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
@@ -577,10 +578,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;
@@ -616,7 +616,20 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
return PTR_ERR(bo);
}
- mutex_lock(&dev->struct_mutex);
+ /* Mark push buffers as being used on PFIFO, the validation code
+ * will then make sure that if the pushbuf bo moves, that they
+ * happen on the kernel channel, which will in turn cause a sync
+ * to happen before we try and submit the push buffer.
+ */
+ for (i = 0; i < req->nr_push; i++) {
+ if (push[i].bo_index >= req->nr_buffers) {
+ NV_ERROR(dev, "push %d buffer not in list\n", i);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ bo[push[i].bo_index].read_domains |= (1 << 31);
+ }
/* Validate buffer list */
ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers,
@@ -650,7 +663,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
push[i].length);
}
} else
- if (dev_priv->card_type >= NV_20) {
+ if (dev_priv->chipset >= 0x25) {
ret = RING_SPACE(chan, req->nr_push * 2);
if (ret) {
NV_ERROR(dev, "cal_space: %d\n", ret);
@@ -716,7 +729,6 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
out:
validate_fini(&op, fence);
nouveau_fence_unref((void**)&fence);
- mutex_unlock(&dev->struct_mutex);
kfree(bo);
kfree(push);
@@ -725,7 +737,7 @@ out_next:
req->suffix0 = 0x00000000;
req->suffix1 = 0x00000000;
} else
- if (dev_priv->card_type >= NV_20) {
+ if (dev_priv->chipset >= 0x25) {
req->suffix0 = 0x00020000;
req->suffix1 = 0x00000000;
} else {
@@ -760,11 +772,9 @@ 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;
+ return -ENOENT;
nvbo = nouveau_gem_object(gem);
if (nvbo->cpu_filp) {
@@ -800,11 +810,9 @@ 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;
+ return -ENOENT;
nvbo = nouveau_gem_object(gem);
if (nvbo->cpu_filp != file_priv)
@@ -827,11 +835,9 @@ 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;
+ return -ENOENT;
ret = nouveau_gem_info(gem, req);
drm_gem_object_unreference_unlocked(gem);
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c
deleted file mode 100644
index f731c5f6053..00000000000
--- a/drivers/gpu/drm/nouveau/nouveau_grctx.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2009 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <linux/firmware.h>
-#include <linux/slab.h>
-
-#include "drmP.h"
-#include "nouveau_drv.h"
-
-struct nouveau_ctxprog {
- uint32_t signature;
- uint8_t version;
- uint16_t length;
- uint32_t data[];
-} __attribute__ ((packed));
-
-struct nouveau_ctxvals {
- uint32_t signature;
- uint8_t version;
- uint32_t length;
- struct {
- uint32_t offset;
- uint32_t value;
- } data[];
-} __attribute__ ((packed));
-
-int
-nouveau_grctx_prog_load(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- const int chipset = dev_priv->chipset;
- const struct firmware *fw;
- const struct nouveau_ctxprog *cp;
- const struct nouveau_ctxvals *cv;
- char name[32];
- int ret, i;
-
- if (pgraph->accel_blocked)
- return -ENODEV;
-
- if (!pgraph->ctxprog) {
- sprintf(name, "nouveau/nv%02x.ctxprog", chipset);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset);
- return ret;
- }
-
- pgraph->ctxprog = kmemdup(fw->data, fw->size, GFP_KERNEL);
- if (!pgraph->ctxprog) {
- NV_ERROR(dev, "OOM copying ctxprog\n");
- release_firmware(fw);
- return -ENOMEM;
- }
-
- cp = pgraph->ctxprog;
- if (le32_to_cpu(cp->signature) != 0x5043564e ||
- cp->version != 0 ||
- le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
- NV_ERROR(dev, "ctxprog invalid\n");
- release_firmware(fw);
- nouveau_grctx_fini(dev);
- return -EINVAL;
- }
- release_firmware(fw);
- }
-
- if (!pgraph->ctxvals) {
- sprintf(name, "nouveau/nv%02x.ctxvals", chipset);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset);
- nouveau_grctx_fini(dev);
- return ret;
- }
-
- pgraph->ctxvals = kmemdup(fw->data, fw->size, GFP_KERNEL);
- if (!pgraph->ctxvals) {
- NV_ERROR(dev, "OOM copying ctxvals\n");
- release_firmware(fw);
- nouveau_grctx_fini(dev);
- return -ENOMEM;
- }
-
- cv = (void *)pgraph->ctxvals;
- if (le32_to_cpu(cv->signature) != 0x5643564e ||
- cv->version != 0 ||
- le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
- NV_ERROR(dev, "ctxvals invalid\n");
- release_firmware(fw);
- nouveau_grctx_fini(dev);
- return -EINVAL;
- }
- release_firmware(fw);
- }
-
- cp = pgraph->ctxprog;
-
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
- for (i = 0; i < le16_to_cpu(cp->length); i++)
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
- le32_to_cpu(cp->data[i]));
-
- return 0;
-}
-
-void
-nouveau_grctx_fini(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-
- if (pgraph->ctxprog) {
- kfree(pgraph->ctxprog);
- pgraph->ctxprog = NULL;
- }
-
- if (pgraph->ctxvals) {
- kfree(pgraph->ctxprog);
- pgraph->ctxvals = NULL;
- }
-}
-
-void
-nouveau_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_ctxvals *cv = pgraph->ctxvals;
- int i;
-
- if (!cv)
- return;
-
- for (i = 0; i < le32_to_cpu(cv->length); i++)
- nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
- le32_to_cpu(cv->data[i].value));
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c
index 7855b35effc..7b613682e40 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hw.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hw.c
@@ -865,8 +865,12 @@ nv_save_state_ext(struct drm_device *dev, int head,
rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
- if (dev_priv->card_type >= NV_30)
+
+ if (dev_priv->card_type >= NV_30) {
rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
+ rd_cio_state(dev, head, regp, 0x9f);
+ }
+
rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX);
@@ -971,8 +975,11 @@ nv_load_state_ext(struct drm_device *dev, int head,
wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX);
wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
- if (dev_priv->card_type >= NV_30)
+
+ if (dev_priv->card_type >= NV_30) {
wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
+ wr_cio_state(dev, head, regp, 0x9f);
+ }
wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index 316a3c7e6eb..84614858728 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -163,7 +163,7 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
if (entry->chan)
return -EEXIST;
- if (dev_priv->card_type == NV_50 && entry->read >= NV50_I2C_PORTS) {
+ if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) {
NV_ERROR(dev, "unknown i2c port %d\n", entry->read);
return -EINVAL;
}
@@ -174,26 +174,26 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
switch (entry->port_type) {
case 0:
- i2c->algo.bit.setsda = nv04_i2c_setsda;
- i2c->algo.bit.setscl = nv04_i2c_setscl;
- i2c->algo.bit.getsda = nv04_i2c_getsda;
- i2c->algo.bit.getscl = nv04_i2c_getscl;
+ i2c->bit.setsda = nv04_i2c_setsda;
+ i2c->bit.setscl = nv04_i2c_setscl;
+ i2c->bit.getsda = nv04_i2c_getsda;
+ i2c->bit.getscl = nv04_i2c_getscl;
i2c->rd = entry->read;
i2c->wr = entry->write;
break;
case 4:
- i2c->algo.bit.setsda = nv4e_i2c_setsda;
- i2c->algo.bit.setscl = nv4e_i2c_setscl;
- i2c->algo.bit.getsda = nv4e_i2c_getsda;
- i2c->algo.bit.getscl = nv4e_i2c_getscl;
+ i2c->bit.setsda = nv4e_i2c_setsda;
+ i2c->bit.setscl = nv4e_i2c_setscl;
+ i2c->bit.getsda = nv4e_i2c_getsda;
+ i2c->bit.getscl = nv4e_i2c_getscl;
i2c->rd = 0x600800 + entry->read;
i2c->wr = 0x600800 + entry->write;
break;
case 5:
- i2c->algo.bit.setsda = nv50_i2c_setsda;
- i2c->algo.bit.setscl = nv50_i2c_setscl;
- i2c->algo.bit.getsda = nv50_i2c_getsda;
- i2c->algo.bit.getscl = nv50_i2c_getscl;
+ i2c->bit.setsda = nv50_i2c_setsda;
+ i2c->bit.setscl = nv50_i2c_setscl;
+ i2c->bit.getsda = nv50_i2c_getsda;
+ i2c->bit.getscl = nv50_i2c_getscl;
i2c->rd = nv50_i2c_port[entry->read];
i2c->wr = i2c->rd;
break;
@@ -216,17 +216,14 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
i2c_set_adapdata(&i2c->adapter, i2c);
if (entry->port_type < 6) {
- i2c->adapter.algo_data = &i2c->algo.bit;
- i2c->algo.bit.udelay = 40;
- i2c->algo.bit.timeout = usecs_to_jiffies(5000);
- i2c->algo.bit.data = i2c;
+ i2c->adapter.algo_data = &i2c->bit;
+ i2c->bit.udelay = 40;
+ i2c->bit.timeout = usecs_to_jiffies(5000);
+ i2c->bit.data = i2c;
ret = i2c_bit_add_bus(&i2c->adapter);
} else {
- i2c->adapter.algo_data = &i2c->algo.dp;
- i2c->algo.dp.running = false;
- i2c->algo.dp.address = 0;
- i2c->algo.dp.aux_ch = nouveau_dp_i2c_aux_ch;
- ret = i2c_dp_aux_add_bus(&i2c->adapter);
+ i2c->adapter.algo = &nouveau_dp_i2c_algo;
+ ret = i2c_add_adapter(&i2c->adapter);
}
if (ret) {
@@ -278,3 +275,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;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h
index c8eaf7a9fcb..f71cb32f757 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.h
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h
@@ -33,10 +33,7 @@ struct dcb_i2c_entry;
struct nouveau_i2c_chan {
struct i2c_adapter adapter;
struct drm_device *dev;
- union {
- struct i2c_algo_bit_data bit;
- struct i2c_algo_dp_aux_data dp;
- } algo;
+ struct i2c_algo_bit_data bit;
unsigned rd;
unsigned wr;
unsigned data;
@@ -45,8 +42,10 @@ 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);
+extern const struct i2c_algorithm nouveau_dp_i2c_algo;
#endif /* __NOUVEAU_I2C_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 53360f15606..794b0ee30cf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -49,7 +49,7 @@ nouveau_irq_preinstall(struct drm_device *dev)
/* Master disable */
nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
- if (dev_priv->card_type == NV_50) {
+ if (dev_priv->card_type >= NV_50) {
INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
INIT_LIST_HEAD(&dev_priv->vbl_waiting);
@@ -586,11 +586,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
}
if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
- nouveau_pgraph_intr_context_switch(dev);
-
status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
nv_wr32(dev, NV03_PGRAPH_INTR,
NV_PGRAPH_INTR_CONTEXT_SWITCH);
+
+ nouveau_pgraph_intr_context_switch(dev);
}
if (status) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index c1fd42b0dad..9689d414768 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -35,162 +35,6 @@
#include "drm_sarea.h"
#include "nouveau_drv.h"
-static struct mem_block *
-split_block(struct mem_block *p, uint64_t start, uint64_t size,
- struct drm_file *file_priv)
-{
- /* Maybe cut off the start of an existing block */
- if (start > p->start) {
- struct mem_block *newblock =
- kmalloc(sizeof(*newblock), GFP_KERNEL);
- if (!newblock)
- goto out;
- newblock->start = start;
- newblock->size = p->size - (start - p->start);
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size -= newblock->size;
- p = newblock;
- }
-
- /* Maybe cut off the end of an existing block */
- if (size < p->size) {
- struct mem_block *newblock =
- kmalloc(sizeof(*newblock), GFP_KERNEL);
- if (!newblock)
- goto out;
- newblock->start = start + size;
- newblock->size = p->size - size;
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size = size;
- }
-
-out:
- /* Our block is in the middle */
- p->file_priv = file_priv;
- return p;
-}
-
-struct mem_block *
-nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size,
- int align2, struct drm_file *file_priv, int tail)
-{
- struct mem_block *p;
- uint64_t mask = (1 << align2) - 1;
-
- if (!heap)
- return NULL;
-
- if (tail) {
- list_for_each_prev(p, heap) {
- uint64_t start = ((p->start + p->size) - size) & ~mask;
-
- if (p->file_priv == NULL && start >= p->start &&
- start + size <= p->start + p->size)
- return split_block(p, start, size, file_priv);
- }
- } else {
- list_for_each(p, heap) {
- uint64_t start = (p->start + mask) & ~mask;
-
- if (p->file_priv == NULL &&
- start + size <= p->start + p->size)
- return split_block(p, start, size, file_priv);
- }
- }
-
- return NULL;
-}
-
-void nouveau_mem_free_block(struct mem_block *p)
-{
- p->file_priv = NULL;
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- if (p->next->file_priv == NULL) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- kfree(q);
- }
-
- if (p->prev->file_priv == NULL) {
- struct mem_block *q = p->prev;
- q->size += p->size;
- q->next = p->next;
- q->next->prev = q;
- kfree(p);
- }
-}
-
-/* Initialize. How to check for an uninitialized heap?
- */
-int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start,
- uint64_t size)
-{
- struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL);
-
- if (!blocks)
- return -ENOMEM;
-
- *heap = kmalloc(sizeof(**heap), GFP_KERNEL);
- if (!*heap) {
- kfree(blocks);
- return -ENOMEM;
- }
-
- blocks->start = start;
- blocks->size = size;
- blocks->file_priv = NULL;
- blocks->next = blocks->prev = *heap;
-
- memset(*heap, 0, sizeof(**heap));
- (*heap)->file_priv = (struct drm_file *) -1;
- (*heap)->next = (*heap)->prev = blocks;
- return 0;
-}
-
-/*
- * Free all blocks associated with the releasing file_priv
- */
-void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap)
-{
- struct mem_block *p;
-
- if (!heap || !heap->next)
- return;
-
- list_for_each(p, heap) {
- if (p->file_priv == file_priv)
- p->file_priv = NULL;
- }
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- list_for_each(p, heap) {
- while ((p->file_priv == NULL) &&
- (p->next->file_priv == NULL) &&
- (p->next != heap)) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- kfree(q);
- }
- }
-}
-
/*
* NV10-NV40 tiling helpers
*/
@@ -299,7 +143,6 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
phys |= 0x30;
}
- dev_priv->engine.instmem.prepare_access(dev, true);
while (size) {
unsigned offset_h = upper_32_bits(phys);
unsigned offset_l = lower_32_bits(phys);
@@ -331,36 +174,12 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
}
}
}
- dev_priv->engine.instmem.finish_access(dev);
-
- nv_wr32(dev, 0x100c80, 0x00050001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00000001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00040001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00060001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
+ dev_priv->engine.instmem.flush(dev);
+ nv50_vm_flush(dev, 5);
+ nv50_vm_flush(dev, 0);
+ nv50_vm_flush(dev, 4);
+ nv50_vm_flush(dev, 6);
return 0;
}
@@ -374,7 +193,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
virt -= dev_priv->vm_vram_base;
pages = (size >> 16) << 1;
- dev_priv->engine.instmem.prepare_access(dev, true);
while (pages) {
pgt = dev_priv->vm_vram_pt[virt >> 29];
pte = (virt & 0x1ffe0000ULL) >> 15;
@@ -388,57 +206,19 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
while (pte < end)
nv_wo32(dev, pgt, pte++, 0);
}
- dev_priv->engine.instmem.finish_access(dev);
-
- nv_wr32(dev, 0x100c80, 0x00050001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return;
- }
-
- nv_wr32(dev, 0x100c80, 0x00000001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return;
- }
-
- nv_wr32(dev, 0x100c80, 0x00040001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return;
- }
+ dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, 0x100c80, 0x00060001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- }
+ nv50_vm_flush(dev, 5);
+ nv50_vm_flush(dev, 0);
+ nv50_vm_flush(dev, 4);
+ nv50_vm_flush(dev, 6);
}
/*
* Cleanup everything
*/
-void nouveau_mem_takedown(struct mem_block **heap)
-{
- struct mem_block *p;
-
- if (!*heap)
- return;
-
- for (p = (*heap)->next; p != *heap;) {
- struct mem_block *q = p;
- p = p->next;
- kfree(q);
- }
-
- kfree(*heap);
- *heap = NULL;
-}
-
-void nouveau_mem_close(struct drm_device *dev)
+void
+nouveau_mem_close(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -449,8 +229,7 @@ void nouveau_mem_close(struct drm_device *dev)
nouveau_ttm_global_release(dev_priv);
- if (drm_core_has_AGP(dev) && dev->agp &&
- drm_core_check_feature(dev, DRIVER_MODESET)) {
+ if (drm_core_has_AGP(dev) && dev->agp) {
struct drm_agp_mem *entry, *tempe;
/* Remove AGP resources, but leave dev->agp
@@ -471,28 +250,29 @@ void nouveau_mem_close(struct drm_device *dev)
}
if (dev_priv->fb_mtrr) {
- drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1),
- drm_get_resource_len(dev, 1), DRM_MTRR_WC);
- dev_priv->fb_mtrr = 0;
+ 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 = -1;
}
}
static uint32_t
nouveau_mem_detect_nv04(struct drm_device *dev)
{
- uint32_t boot0 = nv_rd32(dev, NV03_BOOT_0);
+ uint32_t boot0 = nv_rd32(dev, NV04_PFB_BOOT_0);
if (boot0 & 0x00000100)
return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024;
- switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) {
- case NV04_BOOT_0_RAM_AMOUNT_32MB:
+ switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
return 32 * 1024 * 1024;
- case NV04_BOOT_0_RAM_AMOUNT_16MB:
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
return 16 * 1024 * 1024;
- case NV04_BOOT_0_RAM_AMOUNT_8MB:
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
return 8 * 1024 * 1024;
- case NV04_BOOT_0_RAM_AMOUNT_4MB:
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
return 4 * 1024 * 1024;
}
@@ -536,12 +316,22 @@ 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 {
- 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)
+ } 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
+ if (dev_priv->card_type < NV_C0) {
+ 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;
+ }
+ } else {
+ dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20;
+ dev_priv->vram_size *= nv_rd32(dev, 0x121c74);
}
NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
@@ -555,18 +345,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 (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) {
+ struct drm_agp_info info;
+ struct drm_agp_mode mode;
+
+ ret = drm_agp_info(dev, &info);
+ if (ret)
+ return ret;
+
+ mode.mode = info.mode & ~PCI_AGP_COMMAND_FW;
+ 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);
@@ -578,11 +386,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)
{
@@ -592,11 +401,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) {
@@ -605,6 +409,8 @@ nouveau_mem_init_agp(struct drm_device *dev)
}
}
+ nouveau_mem_reset_agp(dev);
+
ret = drm_agp_info(dev, &info);
if (ret) {
NV_ERROR(dev, "Unable to get AGP info: %d\n", ret);
@@ -633,7 +439,7 @@ nouveau_mem_init(struct drm_device *dev)
struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
int ret, dma_bits = 32;
- dev_priv->fb_phys = drm_get_resource_start(dev, 1);
+ dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
dev_priv->gart_info.type = NOUVEAU_GART_NONE;
if (dev_priv->card_type >= NV_50 &&
@@ -659,14 +465,13 @@ nouveau_mem_init(struct drm_device *dev)
return ret;
}
- INIT_LIST_HEAD(&dev_priv->ttm.bo_list);
- spin_lock_init(&dev_priv->ttm.bo_list_lock);
spin_lock_init(&dev_priv->tile.lock);
dev_priv->fb_available_size = dev_priv->vram_size;
dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
- if (dev_priv->fb_mappable_pages > drm_get_resource_len(dev, 1))
- dev_priv->fb_mappable_pages = drm_get_resource_len(dev, 1);
+ if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1))
+ dev_priv->fb_mappable_pages =
+ pci_resource_len(dev->pdev, 1);
dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
/* remove reserved space at end of vram from available amount */
@@ -692,7 +497,7 @@ 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) {
ret = nouveau_mem_init_agp(dev);
if (ret)
NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
@@ -718,8 +523,8 @@ nouveau_mem_init(struct drm_device *dev)
return ret;
}
- dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1),
- drm_get_resource_len(dev, 1),
+ dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1),
DRM_MTRR_WC);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
index 9537f3e3011..3ec181ff50c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
+++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c
@@ -55,7 +55,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
if (ret)
goto out_err;
- ret = nouveau_mem_init_heap(&chan->notifier_heap, 0, ntfy->bo.mem.size);
+ ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);
if (ret)
goto out_err;
@@ -80,7 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
nouveau_bo_unpin(chan->notifier_bo);
mutex_unlock(&dev->struct_mutex);
drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
- nouveau_mem_takedown(&chan->notifier_heap);
+ drm_mm_takedown(&chan->notifier_heap);
}
static void
@@ -90,7 +90,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
NV_DEBUG(dev, "\n");
if (gpuobj->priv)
- nouveau_mem_free_block(gpuobj->priv);
+ drm_mm_put_block(gpuobj->priv);
}
int
@@ -100,18 +100,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *nobj = NULL;
- struct mem_block *mem;
+ struct drm_mm_node *mem;
uint32_t offset;
int target, ret;
- if (!chan->notifier_heap) {
- NV_ERROR(dev, "Channel %d doesn't have a notifier heap!\n",
- chan->id);
- return -EINVAL;
- }
-
- mem = nouveau_mem_alloc_block(chan->notifier_heap, size, 0,
- (struct drm_file *)-2, 0);
+ mem = drm_mm_search_free(&chan->notifier_heap, size, 0, 0);
+ if (mem)
+ mem = drm_mm_get_block(mem, size, 0);
if (!mem) {
NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
return -ENOMEM;
@@ -144,17 +139,17 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
mem->size, NV_DMA_ACCESS_RW, target,
&nobj);
if (ret) {
- nouveau_mem_free_block(mem);
+ drm_mm_put_block(mem);
NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret);
return ret;
}
- nobj->dtor = nouveau_notifier_gpuobj_dtor;
- nobj->priv = mem;
+ nobj->dtor = nouveau_notifier_gpuobj_dtor;
+ nobj->priv = mem;
ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
if (ret) {
nouveau_gpuobj_del(dev, &nobj);
- nouveau_mem_free_block(mem);
+ drm_mm_put_block(mem);
NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
return ret;
}
@@ -170,7 +165,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)
return -EINVAL;
if (poffset) {
- struct mem_block *mem = nobj->priv;
+ struct drm_mm_node *mem = nobj->priv;
if (*poffset >= mem->size)
return false;
@@ -189,7 +184,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan);
ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset);
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index e7c100ba63a..b6bcb254f4a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -132,7 +132,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
}
}
- instmem->prepare_access(dev, true);
co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
do {
if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
@@ -143,7 +142,7 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
nv_wo32(dev, ramht, (co + 4)/4, ctx);
list_add_tail(&ref->list, &chan->ramht_refs);
- instmem->finish_access(dev);
+ instmem->flush(dev);
return 0;
}
NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
@@ -153,7 +152,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
if (co >= dev_priv->ramht_size)
co = 0;
} while (co != ho);
- instmem->finish_access(dev);
NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
return -ENOMEM;
@@ -173,7 +171,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
return;
}
- instmem->prepare_access(dev, true);
co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
do {
if (nouveau_ramht_entry_valid(dev, ramht, co) &&
@@ -186,7 +183,7 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
nv_wo32(dev, ramht, (co + 4)/4, 0x00000000);
list_del(&ref->list);
- instmem->finish_access(dev);
+ instmem->flush(dev);
return;
}
@@ -195,7 +192,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
co = 0;
} while (co != ho);
list_del(&ref->list);
- instmem->finish_access(dev);
NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
chan->id, ref->handle);
@@ -209,7 +205,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
struct nouveau_gpuobj *gpuobj;
- struct mem_block *pramin = NULL;
+ struct drm_mm *pramin = NULL;
int ret;
NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
@@ -233,25 +229,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
* available.
*/
if (chan) {
- if (chan->ramin_heap) {
- NV_DEBUG(dev, "private heap\n");
- pramin = chan->ramin_heap;
- } else
- if (dev_priv->card_type < NV_50) {
- NV_DEBUG(dev, "global heap fallback\n");
- pramin = dev_priv->ramin_heap;
- }
+ NV_DEBUG(dev, "channel heap\n");
+ pramin = &chan->ramin_heap;
} else {
NV_DEBUG(dev, "global heap\n");
- pramin = dev_priv->ramin_heap;
- }
-
- if (!pramin) {
- NV_ERROR(dev, "No PRAMIN heap!\n");
- return -EINVAL;
- }
+ pramin = &dev_priv->ramin_heap;
- if (!chan) {
ret = engine->instmem.populate(dev, gpuobj, &size);
if (ret) {
nouveau_gpuobj_del(dev, &gpuobj);
@@ -260,9 +243,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
}
/* Allocate a chunk of the PRAMIN aperture */
- gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size,
- drm_order(align),
- (struct drm_file *)-2, 0);
+ gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
+ if (gpuobj->im_pramin)
+ gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
+
if (!gpuobj->im_pramin) {
nouveau_gpuobj_del(dev, &gpuobj);
return -ENOMEM;
@@ -279,10 +263,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
int i;
- engine->instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
nv_wo32(dev, gpuobj, i/4, 0);
- engine->instmem.finish_access(dev);
+ engine->instmem.flush(dev);
}
*gpuobj_ret = gpuobj;
@@ -370,10 +353,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
}
if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
- engine->instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
nv_wo32(dev, gpuobj, i/4, 0);
- engine->instmem.finish_access(dev);
+ engine->instmem.flush(dev);
}
if (gpuobj->dtor)
@@ -386,7 +368,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
if (gpuobj->flags & NVOBJ_FLAG_FAKE)
kfree(gpuobj->im_pramin);
else
- nouveau_mem_free_block(gpuobj->im_pramin);
+ drm_mm_put_block(gpuobj->im_pramin);
}
list_del(&gpuobj->list);
@@ -589,7 +571,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
if (p_offset != ~0) {
- gpuobj->im_pramin = kzalloc(sizeof(struct mem_block),
+ gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
GFP_KERNEL);
if (!gpuobj->im_pramin) {
nouveau_gpuobj_del(dev, &gpuobj);
@@ -605,10 +587,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
}
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
- dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
nv_wo32(dev, gpuobj, i/4, 0);
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
}
if (pref) {
@@ -696,8 +677,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
return ret;
}
- instmem->prepare_access(dev, true);
-
if (dev_priv->card_type < NV_50) {
uint32_t frame, adjust, pte_flags = 0;
@@ -734,7 +713,7 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
nv_wo32(dev, *gpuobj, 5, flags5);
}
- instmem->finish_access(dev);
+ instmem->flush(dev);
(*gpuobj)->engine = NVOBJ_ENGINE_SW;
(*gpuobj)->class = class;
@@ -849,7 +828,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
return ret;
}
- dev_priv->engine.instmem.prepare_access(dev, true);
if (dev_priv->card_type >= NV_50) {
nv_wo32(dev, *gpuobj, 0, class);
nv_wo32(dev, *gpuobj, 5, 0x00010000);
@@ -874,7 +852,7 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
}
}
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
(*gpuobj)->engine = NVOBJ_ENGINE_GR;
(*gpuobj)->class = class;
@@ -920,6 +898,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
base = 0;
/* PGRAPH context */
+ size += dev_priv->engine.graph.grctx_size;
if (dev_priv->card_type == NV_50) {
/* Various fixed table thingos */
@@ -930,12 +909,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
size += 0x8000;
/* RAMFC */
size += 0x1000;
- /* PGRAPH context */
- size += 0x70000;
}
- NV_DEBUG(dev, "ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n",
- chan->id, size, base);
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
&chan->ramin);
if (ret) {
@@ -944,8 +919,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
}
pramin = chan->ramin->gpuobj;
- ret = nouveau_mem_init_heap(&chan->ramin_heap,
- pramin->im_pramin->start + base, size);
+ ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
if (ret) {
NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
nouveau_gpuobj_ref_del(dev, &chan->ramin);
@@ -969,15 +943,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
- /* Reserve a block of PRAMIN for the channel
- *XXX: maybe on <NV50 too at some point
- */
- if (0 || dev_priv->card_type == NV_50) {
- ret = nouveau_gpuobj_channel_init_pramin(chan);
- if (ret) {
- NV_ERROR(dev, "init pramin\n");
- return ret;
- }
+ /* Allocate a chunk of memory for per-channel object storage */
+ ret = nouveau_gpuobj_channel_init_pramin(chan);
+ if (ret) {
+ NV_ERROR(dev, "init pramin\n");
+ return ret;
}
/* NV50 VM
@@ -988,17 +958,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
if (dev_priv->card_type >= NV_50) {
uint32_t vm_offset, pde;
- instmem->prepare_access(dev, true);
-
vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
vm_offset += chan->ramin->gpuobj->im_pramin->start;
ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
0, &chan->vm_pd, NULL);
- if (ret) {
- instmem->finish_access(dev);
+ if (ret)
return ret;
- }
for (i = 0; i < 0x4000; i += 8) {
nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000);
nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe);
@@ -1008,10 +974,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
dev_priv->gart_info.sg_ctxdma,
&chan->vm_gart_pt);
- if (ret) {
- instmem->finish_access(dev);
+ if (ret)
return ret;
- }
nv_wo32(dev, chan->vm_pd, pde++,
chan->vm_gart_pt->instance | 0x03);
nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
@@ -1021,17 +985,15 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
dev_priv->vm_vram_pt[i],
&chan->vm_vram_pt[i]);
- if (ret) {
- instmem->finish_access(dev);
+ if (ret)
return ret;
- }
nv_wo32(dev, chan->vm_pd, pde++,
chan->vm_vram_pt[i]->instance | 0x61);
nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
}
- instmem->finish_access(dev);
+ instmem->flush(dev);
}
/* RAMHT */
@@ -1130,8 +1092,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
- if (chan->ramin_heap)
- nouveau_mem_takedown(&chan->ramin_heap);
+ if (chan->ramin_heap.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);
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 6ca80a3fe70..21a6e453b97 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -1,19 +1,64 @@
+#define NV04_PFB_BOOT_0 0x00100000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
+# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
+# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
+# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
+# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
+#define NV04_PFB_DEBUG_0 0x00100080
+# define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001
+# define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010
+# define NV04_PFB_DEBUG_0_REFRESH_COUNTX64 0x00003f00
+# define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK 0x00004000
+# define NV04_PFB_DEBUG_0_SAFE_MODE 0x00008000
+# define NV04_PFB_DEBUG_0_ALOM_ENABLE 0x00010000
+# define NV04_PFB_DEBUG_0_CASOE 0x00100000
+# define NV04_PFB_DEBUG_0_CKE_INVERT 0x10000000
+# define NV04_PFB_DEBUG_0_REFINC 0x20000000
+# define NV04_PFB_DEBUG_0_SAVE_POWER_OFF 0x40000000
+#define NV04_PFB_CFG0 0x00100200
+# define NV04_PFB_CFG0_SCRAMBLE 0x20000000
+#define NV04_PFB_CFG1 0x00100204
+#define NV04_PFB_FIFO_DATA 0x0010020c
+# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000
+# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20
+#define NV10_PFB_REFCTRL 0x00100210
+# define NV10_PFB_REFCTRL_VALID_1 (1 << 31)
+#define NV04_PFB_PAD 0x0010021c
+# define NV04_PFB_PAD_CKE_NORMAL (1 << 0)
+#define NV10_PFB_TILE(i) (0x00100240 + (i*16))
+#define NV10_PFB_TILE__SIZE 8
+#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16))
+#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16))
+#define NV10_PFB_TSTATUS(i) (0x0010024c + (i*16))
+#define NV04_PFB_REF 0x001002d0
+# define NV04_PFB_REF_CMD_REFRESH (1 << 0)
+#define NV04_PFB_PRE 0x001002d4
+# define NV04_PFB_PRE_CMD_PRECHARGE (1 << 0)
+#define NV10_PFB_CLOSE_PAGE2 0x0010033c
+#define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i))
+#define NV40_PFB_TILE(i) (0x00100600 + (i*16))
+#define NV40_PFB_TILE__SIZE_0 12
+#define NV40_PFB_TILE__SIZE_1 15
+#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16))
+#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16))
+#define NV40_PFB_TSTATUS(i) (0x0010060c + (i*16))
+#define NV40_PFB_UNK_800 0x00100800
-#define NV03_BOOT_0 0x00100000
-# define NV03_BOOT_0_RAM_AMOUNT 0x00000003
-# define NV03_BOOT_0_RAM_AMOUNT_8MB 0x00000000
-# define NV03_BOOT_0_RAM_AMOUNT_2MB 0x00000001
-# define NV03_BOOT_0_RAM_AMOUNT_4MB 0x00000002
-# define NV03_BOOT_0_RAM_AMOUNT_8MB_SDRAM 0x00000003
-# define NV04_BOOT_0_RAM_AMOUNT_32MB 0x00000000
-# define NV04_BOOT_0_RAM_AMOUNT_4MB 0x00000001
-# define NV04_BOOT_0_RAM_AMOUNT_8MB 0x00000002
-# define NV04_BOOT_0_RAM_AMOUNT_16MB 0x00000003
-
-#define NV04_FIFO_DATA 0x0010020c
-# define NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000
-# define NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20
+#define NV_PEXTDEV_BOOT_0 0x00101000
+#define NV_PEXTDEV_BOOT_0_RAMCFG 0x0000003c
+# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12)
+#define NV_PEXTDEV_BOOT_3 0x0010100c
#define NV_RAMIN 0x00700000
@@ -131,23 +176,6 @@
#define NV04_PTIMER_TIME_1 0x00009410
#define NV04_PTIMER_ALARM_0 0x00009420
-#define NV04_PFB_CFG0 0x00100200
-#define NV04_PFB_CFG1 0x00100204
-#define NV40_PFB_020C 0x0010020C
-#define NV10_PFB_TILE(i) (0x00100240 + (i*16))
-#define NV10_PFB_TILE__SIZE 8
-#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16))
-#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16))
-#define NV10_PFB_TSTATUS(i) (0x0010024C + (i*16))
-#define NV10_PFB_CLOSE_PAGE2 0x0010033C
-#define NV40_PFB_TILE(i) (0x00100600 + (i*16))
-#define NV40_PFB_TILE__SIZE_0 12
-#define NV40_PFB_TILE__SIZE_1 15
-#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16))
-#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16))
-#define NV40_PFB_TSTATUS(i) (0x0010060C + (i*16))
-#define NV40_PFB_UNK_800 0x00100800
-
#define NV04_PGRAPH_DEBUG_0 0x00400080
#define NV04_PGRAPH_DEBUG_1 0x00400084
#define NV04_PGRAPH_DEBUG_2 0x00400088
@@ -192,28 +220,21 @@
# define NV_PGRAPH_INTR_ERROR (1<<20)
#define NV10_PGRAPH_CTX_CONTROL 0x00400144
#define NV10_PGRAPH_CTX_USER 0x00400148
-#define NV10_PGRAPH_CTX_SWITCH1 0x0040014C
-#define NV10_PGRAPH_CTX_SWITCH2 0x00400150
-#define NV10_PGRAPH_CTX_SWITCH3 0x00400154
-#define NV10_PGRAPH_CTX_SWITCH4 0x00400158
-#define NV10_PGRAPH_CTX_SWITCH5 0x0040015C
+#define NV10_PGRAPH_CTX_SWITCH(i) (0x0040014C + 0x4*(i))
#define NV04_PGRAPH_CTX_SWITCH1 0x00400160
-#define NV10_PGRAPH_CTX_CACHE1 0x00400160
+#define NV10_PGRAPH_CTX_CACHE(i, j) (0x00400160 \
+ + 0x4*(i) + 0x20*(j))
#define NV04_PGRAPH_CTX_SWITCH2 0x00400164
#define NV04_PGRAPH_CTX_SWITCH3 0x00400168
#define NV04_PGRAPH_CTX_SWITCH4 0x0040016C
#define NV04_PGRAPH_CTX_CONTROL 0x00400170
#define NV04_PGRAPH_CTX_USER 0x00400174
#define NV04_PGRAPH_CTX_CACHE1 0x00400180
-#define NV10_PGRAPH_CTX_CACHE2 0x00400180
#define NV03_PGRAPH_CTX_CONTROL 0x00400190
#define NV03_PGRAPH_CTX_USER 0x00400194
#define NV04_PGRAPH_CTX_CACHE2 0x004001A0
-#define NV10_PGRAPH_CTX_CACHE3 0x004001A0
#define NV04_PGRAPH_CTX_CACHE3 0x004001C0
-#define NV10_PGRAPH_CTX_CACHE4 0x004001C0
#define NV04_PGRAPH_CTX_CACHE4 0x004001E0
-#define NV10_PGRAPH_CTX_CACHE5 0x004001E0
#define NV40_PGRAPH_CTXCTL_0304 0x00400304
#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001
#define NV40_PGRAPH_CTXCTL_UCODE_STAT 0x00400308
@@ -328,9 +349,12 @@
#define NV04_PGRAPH_FFINTFC_ST2 0x00400754
#define NV10_PGRAPH_RDI_DATA 0x00400754
#define NV04_PGRAPH_DMA_PITCH 0x00400760
-#define NV10_PGRAPH_FFINTFC_ST2 0x00400764
+#define NV10_PGRAPH_FFINTFC_FIFO_PTR 0x00400760
#define NV04_PGRAPH_DVD_COLORFMT 0x00400764
+#define NV10_PGRAPH_FFINTFC_ST2 0x00400764
#define NV04_PGRAPH_SCALED_FORMAT 0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DL 0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DH 0x0040076c
#define NV10_PGRAPH_DMA_PITCH 0x00400770
#define NV10_PGRAPH_DVD_COLORFMT 0x00400774
#define NV10_PGRAPH_SCALED_FORMAT 0x00400778
@@ -814,6 +838,7 @@
#define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000
#define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff
#define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_CTRL_ENABLED 0x00000001
#define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000
#define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000
#define NV50_SOR_DP_CTRL_LANE_0_ENABLED 0x00010000
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 1d6ee8b5515..6b9187d7f67 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
NV_DEBUG(dev, "pg=0x%lx\n", mem->mm_node->start);
- dev_priv->engine.instmem.prepare_access(nvbe->dev, true);
pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT);
nvbe->pte_start = pte;
for (i = 0; i < nvbe->nr_pages; i++) {
@@ -116,24 +115,11 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
dma_offset += NV_CTXDMA_PAGE_SIZE;
}
}
- dev_priv->engine.instmem.finish_access(nvbe->dev);
+ dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) {
- nv_wr32(dev, 0x100c80, 0x00050001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
- nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00000001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
- nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
+ nv50_vm_flush(dev, 5); /* PGRAPH */
+ nv50_vm_flush(dev, 0); /* PFIFO */
}
nvbe->bound = true;
@@ -154,7 +140,6 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
if (!nvbe->bound)
return 0;
- dev_priv->engine.instmem.prepare_access(nvbe->dev, true);
pte = nvbe->pte_start;
for (i = 0; i < nvbe->nr_pages; i++) {
dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus;
@@ -170,24 +155,11 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
dma_offset += NV_CTXDMA_PAGE_SIZE;
}
}
- dev_priv->engine.instmem.finish_access(nvbe->dev);
+ dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) {
- nv_wr32(dev, 0x100c80, 0x00050001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
- nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00000001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
- nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
+ nv50_vm_flush(dev, 5);
+ nv50_vm_flush(dev, 0);
}
nvbe->bound = false;
@@ -242,6 +214,7 @@ int
nouveau_sgdma_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct pci_dev *pdev = dev->pdev;
struct nouveau_gpuobj *gpuobj = NULL;
uint32_t aper_size, obj_size;
int i, ret;
@@ -267,12 +240,20 @@ nouveau_sgdma_init(struct drm_device *dev)
dev_priv->gart_info.sg_dummy_page =
alloc_page(GFP_KERNEL|__GFP_DMA32);
+ if (!dev_priv->gart_info.sg_dummy_page) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return -ENOMEM;
+ }
+
set_bit(PG_locked, &dev_priv->gart_info.sg_dummy_page->flags);
dev_priv->gart_info.sg_dummy_bus =
- pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0,
+ pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return -EFAULT;
+ }
- 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 +275,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 +306,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
int pte;
pte = (offset >> NV_CTXDMA_PAGE_SHIFT);
if (dev_priv->card_type < NV_50) {
- instmem->prepare_access(dev, false);
*page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK;
- instmem->finish_access(dev);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index b02a231d693..989322be372 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -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,64 @@ 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;
+ case 0xC0:
+ engine->instmem.init = nvc0_instmem_init;
+ engine->instmem.takedown = nvc0_instmem_takedown;
+ engine->instmem.suspend = nvc0_instmem_suspend;
+ engine->instmem.resume = nvc0_instmem_resume;
+ engine->instmem.populate = nvc0_instmem_populate;
+ engine->instmem.clear = nvc0_instmem_clear;
+ engine->instmem.bind = nvc0_instmem_bind;
+ engine->instmem.unbind = nvc0_instmem_unbind;
+ engine->instmem.flush = nvc0_instmem_flush;
+ engine->mc.init = nv50_mc_init;
+ engine->mc.takedown = nv50_mc_takedown;
+ engine->timer.init = nv04_timer_init;
+ engine->timer.read = nv04_timer_read;
+ engine->timer.takedown = nv04_timer_takedown;
+ engine->fb.init = nvc0_fb_init;
+ engine->fb.takedown = nvc0_fb_takedown;
+ engine->graph.grclass = NULL; //nvc0_graph_grclass;
+ engine->graph.init = nvc0_graph_init;
+ engine->graph.takedown = nvc0_graph_takedown;
+ engine->graph.fifo_access = nvc0_graph_fifo_access;
+ engine->graph.channel = nvc0_graph_channel;
+ engine->graph.create_context = nvc0_graph_create_context;
+ engine->graph.destroy_context = nvc0_graph_destroy_context;
+ engine->graph.load_context = nvc0_graph_load_context;
+ engine->graph.unload_context = nvc0_graph_unload_context;
+ engine->fifo.channels = 128;
+ engine->fifo.init = nvc0_fifo_init;
+ engine->fifo.takedown = nvc0_fifo_takedown;
+ engine->fifo.disable = nvc0_fifo_disable;
+ engine->fifo.enable = nvc0_fifo_enable;
+ engine->fifo.reassign = nvc0_fifo_reassign;
+ engine->fifo.channel_id = nvc0_fifo_channel_id;
+ engine->fifo.create_context = nvc0_fifo_create_context;
+ engine->fifo.destroy_context = nvc0_fifo_destroy_context;
+ engine->fifo.load_context = nvc0_fifo_load_context;
+ engine->fifo.unload_context = nvc0_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 +513,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 +522,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 +564,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 +593,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 +616,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 +638,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 +653,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 +665,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,22 +784,26 @@ 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)
- return -ENOMEM;
+ if (!dev_priv) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
dev->dev_private = dev_priv;
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);
dev_priv->wq = create_workqueue("nouveau");
- if (!dev_priv->wq)
- return -EINVAL;
+ if (!dev_priv->wq) {
+ ret = -EINVAL;
+ goto err_priv;
+ }
/* resource 0 is mmio regs */
/* resource 1 is linear FB */
@@ -719,7 +816,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
if (!dev_priv->mmio) {
NV_ERROR(dev, "Unable to initialize the mmio mapping. "
"Please report your setup to " DRIVER_EMAIL "\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_wq;
}
NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",
(unsigned long long)mmio_start_offs);
@@ -765,19 +863,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
case 0xa0:
dev_priv->card_type = NV_50;
break;
+ case 0xc0:
+ dev_priv->card_type = NV_C0;
+ break;
default:
NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_mmio;
}
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)
+ goto err_mmio;
/* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
if (dev_priv->card_type >= NV_40) {
@@ -791,7 +891,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->ramin_size);
if (!dev_priv->ramin) {
NV_ERROR(dev, "Failed to PRAMIN BAR");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_mmio;
}
} else {
dev_priv->ramin_size = 1 * 1024 * 1024;
@@ -799,7 +900,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->ramin_size);
if (!dev_priv->ramin) {
NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_mmio;
}
}
@@ -812,46 +914,38 @@ 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)
+ goto err_ramin;
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);
+err_ramin:
+ iounmap(dev_priv->ramin);
+err_mmio:
+ iounmap(dev_priv->mmio);
+err_wq:
+ destroy_workqueue(dev_priv->wq);
+err_priv:
+ kfree(dev_priv);
+ dev->dev_private = NULL;
+err_out:
+ return ret;
}
-/* 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 +961,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 +1029,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
{
struct drm_nouveau_setparam *setparam = data;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
switch (setparam->param) {
default:
NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index c385d50f041..bd35f930568 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -42,13 +42,13 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
}
static int
-nouveau_ttm_mem_global_init(struct ttm_global_reference *ref)
+nouveau_ttm_mem_global_init(struct drm_global_reference *ref)
{
return ttm_mem_global_init(ref->object);
}
static void
-nouveau_ttm_mem_global_release(struct ttm_global_reference *ref)
+nouveau_ttm_mem_global_release(struct drm_global_reference *ref)
{
ttm_mem_global_release(ref->object);
}
@@ -56,16 +56,16 @@ nouveau_ttm_mem_global_release(struct ttm_global_reference *ref)
int
nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv)
{
- struct ttm_global_reference *global_ref;
+ struct drm_global_reference *global_ref;
int ret;
global_ref = &dev_priv->ttm.mem_global_ref;
- global_ref->global_type = TTM_GLOBAL_TTM_MEM;
+ global_ref->global_type = DRM_GLOBAL_TTM_MEM;
global_ref->size = sizeof(struct ttm_mem_global);
global_ref->init = &nouveau_ttm_mem_global_init;
global_ref->release = &nouveau_ttm_mem_global_release;
- ret = ttm_global_item_ref(global_ref);
+ ret = drm_global_item_ref(global_ref);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed setting up TTM memory accounting\n");
dev_priv->ttm.mem_global_ref.release = NULL;
@@ -74,15 +74,15 @@ nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv)
dev_priv->ttm.bo_global_ref.mem_glob = global_ref->object;
global_ref = &dev_priv->ttm.bo_global_ref.ref;
- global_ref->global_type = TTM_GLOBAL_TTM_BO;
+ global_ref->global_type = DRM_GLOBAL_TTM_BO;
global_ref->size = sizeof(struct ttm_bo_global);
global_ref->init = &ttm_bo_global_init;
global_ref->release = &ttm_bo_global_release;
- ret = ttm_global_item_ref(global_ref);
+ ret = drm_global_item_ref(global_ref);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed setting up TTM BO subsystem\n");
- ttm_global_item_unref(&dev_priv->ttm.mem_global_ref);
+ drm_global_item_unref(&dev_priv->ttm.mem_global_ref);
dev_priv->ttm.mem_global_ref.release = NULL;
return ret;
}
@@ -96,8 +96,8 @@ nouveau_ttm_global_release(struct drm_nouveau_private *dev_priv)
if (dev_priv->ttm.mem_global_ref.release == NULL)
return;
- ttm_global_item_unref(&dev_priv->ttm.bo_global_ref.ref);
- ttm_global_item_unref(&dev_priv->ttm.mem_global_ref);
+ drm_global_item_unref(&dev_priv->ttm.bo_global_ref.ref);
+ drm_global_item_unref(&dev_priv->ttm.mem_global_ref);
dev_priv->ttm.mem_global_ref.release = NULL;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index eba687f1099..497df8765f2 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -157,6 +157,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
+ struct drm_connector *connector;
unsigned char seq1 = 0, crtc17 = 0;
unsigned char crtc1A;
@@ -211,6 +212,10 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
NVVgaSeqReset(dev, nv_crtc->index, false);
NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A);
+
+ /* Update connector polling modes */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+ nouveau_connector_set_polling(connector);
}
static bool
@@ -537,6 +542,9 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
* 1 << 30 on 0x60.830), for no apparent reason */
regp->CRTC[NV_CIO_CRE_59] = off_chip_digital;
+ if (dev_priv->card_type >= NV_30)
+ regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1;
+
regp->crtc_830 = mode->crtc_vdisplay - 3;
regp->crtc_834 = mode->crtc_vdisplay - 1;
@@ -734,15 +742,13 @@ nv_crtc_gamma_load(struct drm_crtc *crtc)
}
static void
-nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t size)
+nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
+ uint32_t size)
{
+ int end = (start + size > 256) ? 256 : start + size, i;
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- int i;
- if (size != 256)
- return;
-
- for (i = 0; i < 256; i++) {
+ for (i = start; i < end; i++) {
nv_crtc->lut.r[i] = r[i];
nv_crtc->lut.g[i] = g[i];
nv_crtc->lut.b[i] = b[i];
@@ -909,7 +915,7 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
if (!gem)
- return -EINVAL;
+ return -ENOENT;
cursor = nouveau_gem_object(gem);
ret = nouveau_bo_map(cursor);
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
index 1cb19e3acb5..ea3627041ec 100644
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
@@ -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;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
index 41634d4752f..0d3206a7046 100644
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
@@ -34,6 +34,8 @@
#include "nouveau_hw.h"
#include "nvreg.h"
+#include "i2c/sil164.h"
+
#define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \
NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \
NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS)
@@ -144,6 +146,36 @@ void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode)
}
}
+static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+ struct drm_encoder *slave;
+
+ if (dcb->type != OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP)
+ return NULL;
+
+ /* Some BIOSes (e.g. the one in a Quadro FX1000) report several
+ * TMDS transmitters at the same I2C address, in the same I2C
+ * bus. This can still work because in that case one of them is
+ * always hard-wired to a reasonable configuration using straps,
+ * and the other one needs to be programmed.
+ *
+ * I don't think there's a way to know which is which, even the
+ * blob programs the one exposed via I2C for *both* heads, so
+ * let's do the same.
+ */
+ list_for_each_entry(slave, &dev->mode_config.encoder_list, head) {
+ struct dcb_entry *slave_dcb = nouveau_encoder(slave)->dcb;
+
+ if (slave_dcb->type == OUTPUT_TMDS && get_slave_funcs(slave) &&
+ slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr)
+ return slave;
+ }
+
+ return NULL;
+}
+
static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -412,10 +444,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
struct nouveau_encoder *nv_encoder = nouveau_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));
+ struct drm_encoder *slave_encoder;
if (dcbe->type == OUTPUT_TMDS)
run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock);
@@ -433,6 +462,12 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
else
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);
+ /* Init external transmitters */
+ slave_encoder = get_tmds_slave(encoder);
+ if (slave_encoder)
+ get_slave_funcs(slave_encoder)->mode_set(
+ slave_encoder, &nv_encoder->mode, &nv_encoder->mode);
+
helper->dpms(encoder, DRM_MODE_DPMS_ON);
NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
@@ -440,6 +475,27 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
}
+static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode)
+{
+#ifdef __powerpc__
+ struct drm_device *dev = encoder->dev;
+
+ /* BIOS scripts usually take care of the backlight, thanks
+ * Apple for your consistency.
+ */
+ if (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 ||
+ dev->pci_device == 0x0329) {
+ if (mode == DRM_MODE_DPMS_ON) {
+ nv_mask(dev, NV_PBUS_DEBUG_DUALHEAD_CTL, 0, 1 << 31);
+ nv_mask(dev, NV_PCRTC_GPIO_EXT, 3, 1);
+ } else {
+ nv_mask(dev, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 0);
+ nv_mask(dev, NV_PCRTC_GPIO_EXT, 3, 0);
+ }
+ }
+#endif
+}
+
static inline bool is_powersaving_dpms(int mode)
{
return (mode != DRM_MODE_DPMS_ON);
@@ -487,6 +543,7 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
LVDS_PANEL_OFF, 0);
}
+ nv04_dfp_update_backlight(encoder, mode);
nv04_dfp_update_fp_control(encoder, mode);
if (mode == DRM_MODE_DPMS_ON)
@@ -510,6 +567,7 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode)
NV_INFO(dev, "Setting dpms mode %d on tmds encoder (output %d)\n",
mode, nv_encoder->dcb->index);
+ nv04_dfp_update_backlight(encoder, mode);
nv04_dfp_update_fp_control(encoder, mode);
}
@@ -554,10 +612,42 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder)
NV_DEBUG_KMS(encoder->dev, "\n");
+ if (get_slave_funcs(encoder))
+ get_slave_funcs(encoder)->destroy(encoder);
+
drm_encoder_cleanup(encoder);
kfree(nv_encoder);
}
+static void nv04_tmds_slave_init(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+ struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2);
+ struct i2c_board_info info[] = {
+ {
+ .type = "sil164",
+ .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
+ .platform_data = &(struct sil164_encoder_params) {
+ SIL164_INPUT_EDGE_RISING
+ }
+ },
+ { }
+ };
+ int type;
+
+ if (!nv_gf4_disp_arch(dev) || !i2c ||
+ get_tmds_slave(encoder))
+ return;
+
+ type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2);
+ if (type < 0)
+ return;
+
+ drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
+ &i2c->adapter, &info[type]);
+}
+
static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
.dpms = nv04_lvds_dpms,
.save = nv04_dfp_save,
@@ -584,11 +674,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 +704,16 @@ 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;
+ if (entry->type == OUTPUT_TMDS &&
+ entry->location != DCB_LOC_ON_CHIP)
+ nv04_tmds_slave_init(encoder);
+
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index c7898b4f6df..9e28cf772e3 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -32,8 +32,6 @@
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
-#define MULTIPLE_ENCODERS(e) (e & (e - 1))
-
static void
nv04_display_store_initial_head_owner(struct drm_device *dev)
{
@@ -41,7 +39,7 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
if (dev_priv->chipset != 0x11) {
dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44);
- goto ownerknown;
+ return;
}
/* reading CR44 is broken on nv11, so we attempt to infer it */
@@ -52,8 +50,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
bool tvA = false;
bool tvB = false;
- NVLockVgaCrtcs(dev, false);
-
slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) &
0x80;
if (slaved_on_B)
@@ -66,8 +62,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) &
MASK(NV_CIO_CRE_LCD_LCD_SELECT));
- NVLockVgaCrtcs(dev, true);
-
if (slaved_on_A && !tvA)
dev_priv->crtc_owner = 0x0;
else if (slaved_on_B && !tvB)
@@ -79,14 +73,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;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
index 66fe55983b6..06cedd99c26 100644
--- a/drivers/gpu/drm/nouveau/nv04_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
@@ -112,6 +112,12 @@ nv04_fifo_channel_id(struct drm_device *dev)
NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
}
+#ifdef __BIG_ENDIAN
+#define DMA_FETCH_ENDIANNESS NV_PFIFO_CACHE1_BIG_ENDIAN
+#else
+#define DMA_FETCH_ENDIANNESS 0
+#endif
+
int
nv04_fifo_create_context(struct nouveau_channel *chan)
{
@@ -131,18 +137,13 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
/* Setup initial state */
- dev_priv->engine.instmem.prepare_access(dev, true);
RAMFC_WR(DMA_PUT, chan->pushbuf_base);
RAMFC_WR(DMA_GET, chan->pushbuf_base);
RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- 0));
- dev_priv->engine.instmem.finish_access(dev);
+ DMA_FETCH_ENDIANNESS));
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
@@ -169,8 +170,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV04_RAMFC(chid), tmp;
- dev_priv->engine.instmem.prepare_access(dev, false);
-
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
tmp = nv_ri32(dev, fc + 8);
@@ -181,8 +180,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20));
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24));
- dev_priv->engine.instmem.finish_access(dev);
-
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
}
@@ -223,7 +220,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
return -EINVAL;
}
- dev_priv->engine.instmem.prepare_access(dev, true);
RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16;
@@ -233,7 +229,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH));
RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
- dev_priv->engine.instmem.finish_access(dev);
nv04_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
@@ -297,6 +292,7 @@ nv04_fifo_init(struct drm_device *dev)
nv04_fifo_init_intr(dev);
pfifo->enable(dev);
+ pfifo->reassign(dev, true);
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
if (dev_priv->fifos[i]) {
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index 618355e9cdd..c8973421b63 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -342,7 +342,7 @@ static uint32_t nv04_graph_ctx_regs[] = {
};
struct graph_state {
- int nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
+ uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
};
struct nouveau_channel *
@@ -527,8 +527,7 @@ static int
nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass,
int mthd, uint32_t data)
{
- chan->fence.last_sequence_irq = data;
- nouveau_fence_handler(chan->dev, chan->id);
+ atomic_set(&chan->fence.last_sequence_irq, data);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
index a3b9563a6f6..4408232d33f 100644
--- a/drivers/gpu/drm/nouveau/nv04_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
@@ -49,10 +49,8 @@ nv04_instmem_determine_amount(struct drm_device *dev)
NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
/* Clear all of it, except the BIOS image that's in the first 64KiB */
- dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
nv_wi32(dev, i, 0x00000000);
- dev_priv->engine.instmem.finish_access(dev);
}
static void
@@ -106,7 +104,7 @@ int nv04_instmem_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t offset;
- int ret = 0;
+ int ret;
nv04_instmem_determine_amount(dev);
nv04_instmem_configure_fixed_tables(dev);
@@ -129,14 +127,14 @@ int nv04_instmem_init(struct drm_device *dev)
offset = 0x40000;
}
- ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
- offset, dev_priv->ramin_rsvd_vram - offset);
+ ret = drm_mm_init(&dev_priv->ramin_heap, offset,
+ dev_priv->ramin_rsvd_vram - offset);
if (ret) {
- dev_priv->ramin_heap = NULL;
- NV_ERROR(dev, "Failed to init RAMIN heap\n");
+ NV_ERROR(dev, "Failed to init RAMIN heap: %d\n", ret);
+ return ret;
}
- return ret;
+ return 0;
}
void
@@ -186,12 +184,7 @@ nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
}
void
-nv04_instmem_prepare_access(struct drm_device *dev, bool write)
-{
-}
-
-void
-nv04_instmem_finish_access(struct drm_device *dev)
+nv04_instmem_flush(struct drm_device *dev)
{
}
diff --git a/drivers/gpu/drm/nouveau/nv04_mc.c b/drivers/gpu/drm/nouveau/nv04_mc.c
index 617ed1e0526..2af43a1cb2e 100644
--- a/drivers/gpu/drm/nouveau/nv04_mc.c
+++ b/drivers/gpu/drm/nouveau/nv04_mc.c
@@ -11,6 +11,10 @@ nv04_mc_init(struct drm_device *dev)
*/
nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF);
+
+ /* Disable PROM access. */
+ nv_wr32(dev, NV_PBUS_PCI_NV_20, NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
+
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
index c4e3404337d..0b5d012d7c2 100644
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
@@ -34,69 +34,26 @@
#include "i2c/ch7006.h"
-static struct {
- struct i2c_board_info board_info;
- struct drm_encoder_funcs funcs;
- struct drm_encoder_helper_funcs hfuncs;
- void *params;
-
-} nv04_tv_encoder_info[] = {
+static struct i2c_board_info nv04_tv_encoder_info[] = {
{
- .board_info = { I2C_BOARD_INFO("ch7006", 0x75) },
- .params = &(struct ch7006_encoder_params) {
+ I2C_BOARD_INFO("ch7006", 0x75),
+ .platform_data = &(struct ch7006_encoder_params) {
CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER,
0, 0, 0,
CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED,
CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
- },
+ }
},
+ { }
};
-static bool probe_i2c_addr(struct i2c_adapter *adapter, int addr)
-{
- struct i2c_msg msg = {
- .addr = addr,
- .len = 0,
- };
-
- return i2c_transfer(adapter, &msg, 1) == 1;
-}
-
int nv04_tv_identify(struct drm_device *dev, int i2c_index)
{
- struct nouveau_i2c_chan *i2c;
- bool was_locked;
- int i, ret;
-
- NV_TRACE(dev, "Probing TV encoders on I2C bus: %d\n", i2c_index);
-
- i2c = nouveau_i2c_find(dev, i2c_index);
- if (!i2c)
- return -ENODEV;
-
- was_locked = NVLockVgaCrtcs(dev, false);
-
- for (i = 0; i < ARRAY_SIZE(nv04_tv_encoder_info); i++) {
- if (probe_i2c_addr(&i2c->adapter,
- nv04_tv_encoder_info[i].board_info.addr)) {
- ret = i;
- break;
- }
- }
-
- if (i < ARRAY_SIZE(nv04_tv_encoder_info)) {
- NV_TRACE(dev, "Detected TV encoder: %s\n",
- nv04_tv_encoder_info[i].board_info.type);
-
- } else {
- NV_TRACE(dev, "No TV encoders found.\n");
- i = -ENODEV;
- }
-
- NVLockVgaCrtcs(dev, was_locked);
- return i;
+ return nouveau_i2c_identify(dev, "TV encoder",
+ nv04_tv_encoder_info, i2c_index);
}
+
#define PLLSEL_TV_CRTC1_MASK \
(NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \
| NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1)
@@ -132,7 +89,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel);
- to_encoder_slave(encoder)->slave_funcs->dpms(encoder, mode);
+ get_slave_funcs(encoder)->dpms(encoder, mode);
}
static void nv04_tv_bind(struct drm_device *dev, int head, bool bind)
@@ -195,7 +152,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder,
regp->tv_vskew = 1;
regp->tv_vsync_delay = 1;
- to_encoder_slave(encoder)->slave_funcs->mode_set(encoder, mode, adjusted_mode);
+ get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode);
}
static void nv04_tv_commit(struct drm_encoder *encoder)
@@ -214,30 +171,31 @@ 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);
-
+ get_slave_funcs(encoder)->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,40 +204,31 @@ 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,
- };
+ sfuncs = get_slave_funcs(encoder);
*hfuncs = (struct drm_encoder_helper_funcs) {
.dpms = nv04_tv_dpms,
@@ -292,14 +241,16 @@ 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->create_resources(encoder, connector);
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
-fail:
+fail_cleanup:
drm_encoder_cleanup(encoder);
-
+ kfree(hfuncs);
+fail_free:
kfree(nv_encoder);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c
index 7aeabf262bc..7a4069cf5d0 100644
--- a/drivers/gpu/drm/nouveau/nv10_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv10_fifo.c
@@ -55,7 +55,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
/* Fill entries that are seen filled in dumps of nvidia driver just
* after channel's is put into DMA mode
*/
- dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
@@ -66,7 +65,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
0);
- dev_priv->engine.instmem.finish_access(dev);
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
@@ -91,8 +89,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV10_RAMFC(chid), tmp;
- dev_priv->engine.instmem.prepare_access(dev, false);
-
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
@@ -117,8 +113,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 48));
out:
- dev_priv->engine.instmem.finish_access(dev);
-
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
}
@@ -155,8 +149,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
return 0;
fc = NV10_RAMFC(chid);
- dev_priv->engine.instmem.prepare_access(dev, true);
-
nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
@@ -179,8 +171,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
nv_wi32(dev, fc + 48, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
out:
- dev_priv->engine.instmem.finish_access(dev);
-
nv10_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nv17_gpio.c b/drivers/gpu/drm/nouveau/nv10_gpio.c
index 2e58c331e9b..007fc29e2f8 100644
--- a/drivers/gpu/drm/nouveau/nv17_gpio.c
+++ b/drivers/gpu/drm/nouveau/nv10_gpio.c
@@ -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;
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index fcf2cdd1949..b2f6a57c0cc 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -43,51 +43,51 @@ struct pipe_state {
};
static int nv10_graph_ctx_regs[] = {
- NV10_PGRAPH_CTX_SWITCH1,
- NV10_PGRAPH_CTX_SWITCH2,
- NV10_PGRAPH_CTX_SWITCH3,
- NV10_PGRAPH_CTX_SWITCH4,
- NV10_PGRAPH_CTX_SWITCH5,
- NV10_PGRAPH_CTX_CACHE1, /* 8 values from 0x400160 to 0x40017c */
- NV10_PGRAPH_CTX_CACHE2, /* 8 values from 0x400180 to 0x40019c */
- NV10_PGRAPH_CTX_CACHE3, /* 8 values from 0x4001a0 to 0x4001bc */
- NV10_PGRAPH_CTX_CACHE4, /* 8 values from 0x4001c0 to 0x4001dc */
- NV10_PGRAPH_CTX_CACHE5, /* 8 values from 0x4001e0 to 0x4001fc */
- 0x00400164,
- 0x00400184,
- 0x004001a4,
- 0x004001c4,
- 0x004001e4,
- 0x00400168,
- 0x00400188,
- 0x004001a8,
- 0x004001c8,
- 0x004001e8,
- 0x0040016c,
- 0x0040018c,
- 0x004001ac,
- 0x004001cc,
- 0x004001ec,
- 0x00400170,
- 0x00400190,
- 0x004001b0,
- 0x004001d0,
- 0x004001f0,
- 0x00400174,
- 0x00400194,
- 0x004001b4,
- 0x004001d4,
- 0x004001f4,
- 0x00400178,
- 0x00400198,
- 0x004001b8,
- 0x004001d8,
- 0x004001f8,
- 0x0040017c,
- 0x0040019c,
- 0x004001bc,
- 0x004001dc,
- 0x004001fc,
+ NV10_PGRAPH_CTX_SWITCH(0),
+ NV10_PGRAPH_CTX_SWITCH(1),
+ NV10_PGRAPH_CTX_SWITCH(2),
+ NV10_PGRAPH_CTX_SWITCH(3),
+ NV10_PGRAPH_CTX_SWITCH(4),
+ NV10_PGRAPH_CTX_CACHE(0, 0),
+ NV10_PGRAPH_CTX_CACHE(0, 1),
+ NV10_PGRAPH_CTX_CACHE(0, 2),
+ NV10_PGRAPH_CTX_CACHE(0, 3),
+ NV10_PGRAPH_CTX_CACHE(0, 4),
+ NV10_PGRAPH_CTX_CACHE(1, 0),
+ NV10_PGRAPH_CTX_CACHE(1, 1),
+ NV10_PGRAPH_CTX_CACHE(1, 2),
+ NV10_PGRAPH_CTX_CACHE(1, 3),
+ NV10_PGRAPH_CTX_CACHE(1, 4),
+ NV10_PGRAPH_CTX_CACHE(2, 0),
+ NV10_PGRAPH_CTX_CACHE(2, 1),
+ NV10_PGRAPH_CTX_CACHE(2, 2),
+ NV10_PGRAPH_CTX_CACHE(2, 3),
+ NV10_PGRAPH_CTX_CACHE(2, 4),
+ NV10_PGRAPH_CTX_CACHE(3, 0),
+ NV10_PGRAPH_CTX_CACHE(3, 1),
+ NV10_PGRAPH_CTX_CACHE(3, 2),
+ NV10_PGRAPH_CTX_CACHE(3, 3),
+ NV10_PGRAPH_CTX_CACHE(3, 4),
+ NV10_PGRAPH_CTX_CACHE(4, 0),
+ NV10_PGRAPH_CTX_CACHE(4, 1),
+ NV10_PGRAPH_CTX_CACHE(4, 2),
+ NV10_PGRAPH_CTX_CACHE(4, 3),
+ NV10_PGRAPH_CTX_CACHE(4, 4),
+ NV10_PGRAPH_CTX_CACHE(5, 0),
+ NV10_PGRAPH_CTX_CACHE(5, 1),
+ NV10_PGRAPH_CTX_CACHE(5, 2),
+ NV10_PGRAPH_CTX_CACHE(5, 3),
+ NV10_PGRAPH_CTX_CACHE(5, 4),
+ NV10_PGRAPH_CTX_CACHE(6, 0),
+ NV10_PGRAPH_CTX_CACHE(6, 1),
+ NV10_PGRAPH_CTX_CACHE(6, 2),
+ NV10_PGRAPH_CTX_CACHE(6, 3),
+ NV10_PGRAPH_CTX_CACHE(6, 4),
+ NV10_PGRAPH_CTX_CACHE(7, 0),
+ NV10_PGRAPH_CTX_CACHE(7, 1),
+ NV10_PGRAPH_CTX_CACHE(7, 2),
+ NV10_PGRAPH_CTX_CACHE(7, 3),
+ NV10_PGRAPH_CTX_CACHE(7, 4),
NV10_PGRAPH_CTX_USER,
NV04_PGRAPH_DMA_START_0,
NV04_PGRAPH_DMA_START_1,
@@ -653,6 +653,78 @@ static int nv17_graph_ctx_regs_find_offset(struct drm_device *dev, int reg)
return -1;
}
+static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
+ uint32_t inst)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
+ uint32_t ctx_user, ctx_switch[5];
+ int i, subchan = -1;
+
+ /* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
+ * that cannot be restored via MMIO. Do it through the FIFO
+ * instead.
+ */
+
+ /* Look for a celsius object */
+ for (i = 0; i < 8; i++) {
+ int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
+
+ if (class == 0x56 || class == 0x96 || class == 0x99) {
+ subchan = i;
+ break;
+ }
+ }
+
+ if (subchan < 0 || !inst)
+ return;
+
+ /* Save the current ctx object */
+ ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
+ for (i = 0; i < 5; i++)
+ ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i));
+
+ /* Save the FIFO state */
+ st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
+ st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL);
+ st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH);
+ fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR);
+
+ for (i = 0; i < ARRAY_SIZE(fifo); i++)
+ fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i);
+
+ /* Switch to the celsius subchannel */
+ for (i = 0; i < 5; i++)
+ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i),
+ nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i)));
+ nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
+
+ /* Inject NV10TCL_DMA_VTXBUF */
+ nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
+ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2,
+ 0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
+ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
+ nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
+ pgraph->fifo_access(dev, true);
+ pgraph->fifo_access(dev, false);
+
+ /* Restore the FIFO state */
+ for (i = 0; i < ARRAY_SIZE(fifo); i++)
+ nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]);
+
+ nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
+ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2);
+ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
+ nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
+
+ /* Restore the current ctx object */
+ for (i = 0; i < 5; i++)
+ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
+ nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
+}
+
int nv10_graph_load_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
@@ -670,6 +742,8 @@ int nv10_graph_load_context(struct nouveau_channel *chan)
}
nv10_graph_load_pipe(chan);
+ nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1)
+ & 0xffff));
nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
@@ -856,11 +930,12 @@ int nv10_graph_init(struct drm_device *dev)
for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
nv10_graph_set_region_tiling(dev, i, 0, 0, 0);
- nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH1, 0x00000000);
- nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH2, 0x00000000);
- nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH3, 0x00000000);
- nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH4, 0x00000000);
- nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF);
+ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
+ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
+ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
+ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
+ nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
+ nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF);
tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
tmp |= (dev_priv->engine.fifo.channels - 1) << 24;
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
index 74c880374fb..13cdc05b7c2 100644
--- a/drivers/gpu/drm/nouveau/nv17_tv.c
+++ b/drivers/gpu/drm/nouveau/nv17_tv.c
@@ -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,31 @@ 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 (nv_match_device(dev, 0x0322, 0x19da, 0x1035) ||
+ nv_match_device(dev, 0x0322, 0x19da, 0x2035)) {
+ *pin_mask = 0xc;
+ return false;
+ }
+
+ /* MSI nForce2 IGP */
+ if (nv_match_device(dev, 0x01f0, 0x1462, 0x5710)) {
+ *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 +144,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 +182,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 +326,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 +340,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 +366,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 +779,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 +811,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
+ nv17_tv_create_resources(encoder, connector);
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index d6fc0a82f03..17f309b36c9 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -370,68 +370,54 @@ nv20_graph_create_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
- unsigned int ctx_size;
unsigned int idoffs = 0x28/4;
int ret;
switch (dev_priv->chipset) {
case 0x20:
- ctx_size = NV20_GRCTX_SIZE;
ctx_init = nv20_graph_context_init;
idoffs = 0;
break;
case 0x25:
case 0x28:
- ctx_size = NV25_GRCTX_SIZE;
ctx_init = nv25_graph_context_init;
break;
case 0x2a:
- ctx_size = NV2A_GRCTX_SIZE;
ctx_init = nv2a_graph_context_init;
idoffs = 0;
break;
case 0x30:
case 0x31:
- ctx_size = NV30_31_GRCTX_SIZE;
ctx_init = nv30_31_graph_context_init;
break;
case 0x34:
- ctx_size = NV34_GRCTX_SIZE;
ctx_init = nv34_graph_context_init;
break;
case 0x35:
case 0x36:
- ctx_size = NV35_36_GRCTX_SIZE;
ctx_init = nv35_36_graph_context_init;
break;
default:
- ctx_size = 0;
- ctx_init = nv35_36_graph_context_init;
- NV_ERROR(dev, "Please contact the devs if you want your NV%x"
- " card to work\n", dev_priv->chipset);
- return -ENOSYS;
- break;
+ BUG_ON(1);
}
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &chan->ramin_grctx);
+ ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
+ 16, NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->ramin_grctx);
if (ret)
return ret;
/* Initialise default context values */
- dev_priv->engine.instmem.prepare_access(dev, true);
ctx_init(dev, chan->ramin_grctx->gpuobj);
/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs,
(chan->id << 24) | 0x1); /* CTX_USER */
- nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id,
- chan->ramin_grctx->instance >> 4);
-
- dev_priv->engine.instmem.finish_access(dev);
+ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id,
+ chan->ramin_grctx->instance >> 4);
return 0;
}
@@ -440,13 +426,12 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
if (chan->ramin_grctx)
nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
- dev_priv->engine.instmem.prepare_access(dev, true);
- nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0);
- dev_priv->engine.instmem.finish_access(dev);
+ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0);
}
int
@@ -538,29 +523,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
int
nv20_graph_init(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv =
- (struct drm_nouveau_private *)dev->dev_private;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
uint32_t tmp, vramsz;
int ret, i;
+ switch (dev_priv->chipset) {
+ case 0x20:
+ pgraph->grctx_size = NV20_GRCTX_SIZE;
+ break;
+ case 0x25:
+ case 0x28:
+ pgraph->grctx_size = NV25_GRCTX_SIZE;
+ break;
+ case 0x2a:
+ pgraph->grctx_size = NV2A_GRCTX_SIZE;
+ break;
+ default:
+ NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
+ pgraph->accel_blocked = true;
+ return 0;
+ }
+
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
- if (!dev_priv->ctx_table) {
+ if (!pgraph->ctx_table) {
/* Create Context Pointer Table */
- dev_priv->ctx_table_size = 32 * 4;
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
- dev_priv->ctx_table_size, 16,
+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC,
- &dev_priv->ctx_table);
+ &pgraph->ctx_table);
if (ret)
return ret;
}
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
- dev_priv->ctx_table->instance >> 4);
+ pgraph->ctx_table->instance >> 4);
nv20_graph_rdi(dev);
@@ -616,7 +616,7 @@ nv20_graph_init(struct drm_device *dev)
nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp);
/* begin RAM config */
- vramsz = drm_get_resource_len(dev, 0) - 1;
+ vramsz = pci_resource_len(dev->pdev, 0) - 1;
nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
@@ -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);
@@ -717,7 +735,7 @@ nv30_graph_init(struct drm_device *dev)
nv_wr32(dev, 0x0040075c , 0x00000001);
/* begin RAM config */
- /* vramsz = drm_get_resource_len(dev, 0) - 1; */
+ /* vramsz = pci_resource_len(dev->pdev, 0) - 1; */
nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
if (dev_priv->chipset != 0x34) {
diff --git a/drivers/gpu/drm/nouveau/nv30_fb.c b/drivers/gpu/drm/nouveau/nv30_fb.c
new file mode 100644
index 00000000000..4a3f2f09512
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv30_fb.c
@@ -0,0 +1,95 @@
+/*
+ * 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_bias(struct drm_device *dev, int k, int i, int j)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int b = (dev_priv->chipset > 0x30 ?
+ nv_rd32(dev, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) :
+ 0) & 0xf;
+
+ return 2 * (b & 0x8 ? b - 0x10 : b);
+}
+
+static int
+calc_ref(struct drm_device *dev, int l, int k, int i)
+{
+ int j, x = 0;
+
+ for (j = 0; j < 4; j++) {
+ int m = (l >> (8 * i) & 0xff) + calc_bias(dev, k, i, j);
+
+ x |= (0x80 | clamp(m, 0, 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 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(dev, l, 0, j));
+
+ for (j = 0; j < 2; j++)
+ nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j,
+ calc_ref(dev, l, 1, j));
+ }
+ }
+
+ return 0;
+}
+
+void
+nv30_fb_takedown(struct drm_device *dev)
+{
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
index 500ccfd3a0b..2b67f1835c3 100644
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -48,7 +48,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
@@ -61,7 +60,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
0x30000000 /* no idea.. */);
nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
nv_wi32(dev, fc + 60, 0x0001FFFF);
- dev_priv->engine.instmem.finish_access(dev);
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
@@ -89,8 +87,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV40_RAMFC(chid), tmp, tmp2;
- dev_priv->engine.instmem.prepare_access(dev, false);
-
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
@@ -127,8 +123,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
- dev_priv->engine.instmem.finish_access(dev);
-
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
}
@@ -166,7 +160,6 @@ nv40_fifo_unload_context(struct drm_device *dev)
return 0;
fc = NV40_RAMFC(chid);
- dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
@@ -200,7 +193,6 @@ nv40_fifo_unload_context(struct drm_device *dev)
tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
nv_wi32(dev, fc + 72, tmp);
#endif
- dev_priv->engine.instmem.finish_access(dev);
nv40_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index 704a25d04ac..fd7d2b50131 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -58,6 +58,7 @@ nv40_graph_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_grctx ctx = {};
int ret;
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
@@ -67,20 +68,13 @@ nv40_graph_create_context(struct nouveau_channel *chan)
return ret;
/* Initialise default context values */
- dev_priv->engine.instmem.prepare_access(dev, true);
- if (!pgraph->ctxprog) {
- struct nouveau_grctx ctx = {};
-
- ctx.dev = chan->dev;
- ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = chan->ramin_grctx->gpuobj;
- nv40_grctx_init(&ctx);
- } else {
- nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj);
- }
+ ctx.dev = chan->dev;
+ ctx.mode = NOUVEAU_GRCTX_VALS;
+ ctx.data = chan->ramin_grctx->gpuobj;
+ nv40_grctx_init(&ctx);
+
nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
chan->ramin_grctx->gpuobj->im_pramin->start);
- dev_priv->engine.instmem.finish_access(dev);
return 0;
}
@@ -238,7 +232,8 @@ nv40_graph_init(struct drm_device *dev)
struct drm_nouveau_private *dev_priv =
(struct drm_nouveau_private *)dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
- uint32_t vramsz;
+ struct nouveau_grctx ctx = {};
+ uint32_t vramsz, *cp;
int i, j;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
@@ -246,32 +241,22 @@ nv40_graph_init(struct drm_device *dev)
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
- if (nouveau_ctxfw) {
- nouveau_grctx_prog_load(dev);
- dev_priv->engine.graph.grctx_size = 175 * 1024;
- }
+ cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
+ if (!cp)
+ return -ENOMEM;
- if (!dev_priv->engine.graph.ctxprog) {
- struct nouveau_grctx ctx = {};
- uint32_t *cp;
+ ctx.dev = dev;
+ ctx.mode = NOUVEAU_GRCTX_PROG;
+ ctx.data = cp;
+ ctx.ctxprog_max = 256;
+ nv40_grctx_init(&ctx);
+ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
- cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
- if (!cp)
- return -ENOMEM;
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < ctx.ctxprog_len; i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
- ctx.dev = dev;
- ctx.mode = NOUVEAU_GRCTX_PROG;
- ctx.data = cp;
- ctx.ctxprog_max = 256;
- nv40_grctx_init(&ctx);
- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
-
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
- for (i = 0; i < ctx.ctxprog_len; i++)
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
-
- kfree(cp);
- }
+ kfree(cp);
/* No context present currently */
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
@@ -367,7 +352,7 @@ nv40_graph_init(struct drm_device *dev)
nv40_graph_set_region_tiling(dev, i, 0, 0, 0);
/* begin RAM config */
- vramsz = drm_get_resource_len(dev, 0) - 1;
+ vramsz = pci_resource_len(dev->pdev, 0) - 1;
switch (dev_priv->chipset) {
case 0x40:
nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
@@ -407,7 +392,6 @@ nv40_graph_init(struct drm_device *dev)
void nv40_graph_takedown(struct drm_device *dev)
{
- nouveau_grctx_fini(dev);
}
struct nouveau_pgraph_object_class nv40_graph_grclass[] = {
diff --git a/drivers/gpu/drm/nouveau/nv40_mc.c b/drivers/gpu/drm/nouveau/nv40_mc.c
index 2a3495e848e..e4e72c12ab6 100644
--- a/drivers/gpu/drm/nouveau/nv40_mc.c
+++ b/drivers/gpu/drm/nouveau/nv40_mc.c
@@ -19,7 +19,7 @@ nv40_mc_init(struct drm_device *dev)
case 0x46: /* G72 */
case 0x4e:
case 0x4c: /* C51_G7X */
- tmp = nv_rd32(dev, NV40_PFB_020C);
+ tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA);
nv_wr32(dev, NV40_PMC_1700, tmp);
nv_wr32(dev, NV40_PMC_1704, 0);
nv_wr32(dev, NV40_PMC_1708, 0);
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index b4e4a3b05ea..bfd4ca2fe7e 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -264,11 +264,16 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update)
int
nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
{
- uint32_t reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct pll_lims pll;
- uint32_t reg1, reg2;
+ uint32_t reg, reg1, reg2;
int ret, N1, M1, N2, M2, P;
+ if (dev_priv->chipset < NV_C0)
+ reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
+ else
+ reg = 0x614140 + (head * 0x800);
+
ret = get_pll_limits(dev, reg, &pll);
if (ret)
return ret;
@@ -286,7 +291,8 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
nv_wr32(dev, reg, 0x10000611);
nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1);
nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
- } else {
+ } else
+ if (dev_priv->chipset < NV_C0) {
ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
if (ret <= 0)
return 0;
@@ -298,6 +304,17 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
nv_wr32(dev, reg, 0x50000610);
nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
nv_wr32(dev, reg + 8, N2);
+ } else {
+ ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+ if (ret <= 0)
+ return 0;
+
+ NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
+ pclk, ret, N1, N2, M1, P);
+
+ nv_mask(dev, reg + 0x0c, 0x00000000, 0x00000100);
+ nv_wr32(dev, reg + 0x04, (P << 16) | (N1 << 8) | M1);
+ nv_wr32(dev, reg + 0x10, N2 << 16);
}
return 0;
@@ -348,7 +365,7 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
if (!gem)
- return -EINVAL;
+ return -ENOENT;
cursor = nouveau_gem_object(gem);
ret = nouveau_bo_map(cursor);
@@ -381,15 +398,12 @@ nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
static void
nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
- uint32_t size)
+ uint32_t start, uint32_t size)
{
+ int end = (start + size > 256) ? 256 : start + size, i;
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- int i;
-
- if (size != 256)
- return;
- for (i = 0; i < 256; i++) {
+ for (i = start; i < end; i++) {
nv_crtc->lut.r[i] = r[i];
nv_crtc->lut.g[i] = g[i];
nv_crtc->lut.b[i] = b[i];
@@ -440,47 +454,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 +473,14 @@ nv50_crtc_commit(struct drm_crtc *crtc)
nv50_crtc_blank(nv_crtc, false);
- /* Explicitly blank all unused crtc's. */
- list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) {
- if (!drm_helper_crtc_in_use(crtc2))
- nv50_crtc_blank(nouveau_crtc(crtc2), true);
- }
-
ret = RING_SPACE(evo, 2);
if (ret) {
NV_ERROR(dev, "no space while committing crtc\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
- OUT_RING(evo, 0);
- FIRE_RING(evo);
+ OUT_RING (evo, 0);
+ FIRE_RING (evo);
}
static bool
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
index 1fd9537beff..1bc08596294 100644
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -37,22 +37,31 @@
#include "nv50_display.h"
static void
-nv50_dac_disconnect(struct nouveau_encoder *nv_encoder)
+nv50_dac_disconnect(struct drm_encoder *encoder)
{
- struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
int ret;
+ if (!nv_encoder->crtc)
+ return;
+ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
+
NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
- ret = RING_SPACE(evo, 2);
+ ret = RING_SPACE(evo, 4);
if (ret) {
NV_ERROR(dev, "no space while disconnecting DAC\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
- OUT_RING(evo, 0);
+ OUT_RING (evo, 0);
+ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING (evo, 0);
+
+ nv_encoder->crtc = NULL;
}
static enum drm_connector_status
@@ -213,7 +222,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
uint32_t mode_ctl = 0, mode_ctl2 = 0;
int ret;
- NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "or %d type %d crtc %d\n",
+ nv_encoder->or, nv_encoder->dcb->type, crtc->index);
nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
@@ -243,6 +253,14 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
OUT_RING(evo, mode_ctl);
OUT_RING(evo, mode_ctl2);
+
+ nv_encoder->crtc = encoder->crtc;
+}
+
+static struct drm_crtc *
+nv50_dac_crtc_get(struct drm_encoder *encoder)
+{
+ return nouveau_encoder(encoder)->crtc;
}
static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
@@ -253,7 +271,9 @@ static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
.prepare = nv50_dac_prepare,
.commit = nv50_dac_commit,
.mode_set = nv50_dac_mode_set,
- .detect = nv50_dac_detect
+ .get_crtc = nv50_dac_crtc_get,
+ .detect = nv50_dac_detect,
+ .disable = nv50_dac_disconnect
};
static void
@@ -275,14 +295,11 @@ static const struct drm_encoder_funcs nv50_dac_encoder_funcs = {
};
int
-nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
+nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
{
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
- NV_DEBUG_KMS(dev, "\n");
- NV_INFO(dev, "Detected a DAC output\n");
-
nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
if (!nv_encoder)
return -ENOMEM;
@@ -291,14 +308,14 @@ nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
- nv_encoder->disconnect = nv50_dac_disconnect;
-
- drm_encoder_init(dev, encoder, &nv50_dac_encoder_funcs,
+ drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
DRM_MODE_ENCODER_DAC);
drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
+
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 580a5d10be9..612fa6d6a0c 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -71,14 +71,16 @@ 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);
+ if (dev_priv->card_type < NV_C0)
+ nv_wo32(dev, obj, 5, 0x00010000);
+ else
+ nv_wo32(dev, obj, 5, 0x00020000);
+ dev_priv->engine.instmem.flush(dev);
return 0;
}
@@ -110,8 +112,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);
@@ -179,13 +181,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
}
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 +380,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 +466,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 +509,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 +528,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 +546,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 +557,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);
- if (!(mc & (1 << head)))
- continue;
-
- switch ((mc >> 8) & 0xf) {
- case 0: type = OUTPUT_ANALOG; break;
- case 1: type = OUTPUT_TV; break;
- default:
- NV_ERROR(dev, "unknown dac mode_ctrl: 0x%08x\n", dac);
- return -1;
- }
-
- or = i;
- }
-
- for (i = 0; i < 4 && type == OUTPUT_ANY; i++) {
- uint32_t mc = nv50_display_mode_ctrl(dev, true, i);
- if (!(mc & (1 << head)))
- continue;
-
- switch ((mc >> 8) & 0xf) {
- case 0: type = OUTPUT_LVDS; break;
- case 1: type = OUTPUT_TMDS; break;
- case 2: type = OUTPUT_TMDS; break;
- case 5: type = OUTPUT_TMDS; break;
- case 8: type = OUTPUT_DP; break;
- case 9: type = OUTPUT_DP; break;
- default:
- NV_ERROR(dev, "unknown sor mode_ctrl: 0x%08x\n", sor);
- return -1;
- }
-
- or = i;
- }
-
- NV_DEBUG_KMS(dev, "type %d, or %d\n", type, or);
- if (type == OUTPUT_ANY) {
- NV_ERROR(dev, "unknown encoder!!\n");
- return -1;
- }
-
- for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
- struct dcb_entry *dcbent = &dev_priv->vbios.dcb.entry[i];
-
- if (dcbent->type != type)
- continue;
-
- if (!(dcbent->or & (1 << or)))
- continue;
-
- *phead = head;
- *pdcbent = dcbent;
- return 0;
- }
-
- NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or);
- return 0;
}
-static uint32_t
-nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent,
- int pxclk)
+static u16
+nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
+ u32 mc, int pxclk)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = NULL;
struct drm_encoder *encoder;
struct nvbios *bios = &dev_priv->vbios;
- uint32_t mc, script = 0, or;
+ u32 script = 0, or;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- if (nv_encoder->dcb != dcbent)
+ if (nv_encoder->dcb != dcb)
continue;
nv_connector = nouveau_encoder_connector_get(nv_encoder);
break;
}
- or = ffs(dcbent->or) - 1;
- mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or);
- switch (dcbent->type) {
+ or = ffs(dcb->or) - 1;
+ switch (dcb->type) {
case OUTPUT_LVDS:
script = (mc >> 8) & 0xf;
if (bios->fp_no_ddc) {
@@ -767,17 +671,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
static void
nv50_display_unk10_handler(struct drm_device *dev)
{
- struct dcb_entry *dcbent;
- int head, ret;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 unk30 = nv_rd32(dev, 0x610030), mc;
+ int i, crtc, or, type = OUTPUT_ANY;
- ret = nv50_display_irq_head(dev, &head, &dcbent);
- if (ret)
- goto ack;
+ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+ dev_priv->evo_irq.dcb = NULL;
nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8);
- nouveau_bios_run_display_table(dev, dcbent, 0, -1);
+ /* Determine which CRTC we're dealing with, only 1 ever will be
+ * signalled at the same time with the current nouveau code.
+ */
+ crtc = ffs((unk30 & 0x00000060) >> 5) - 1;
+ if (crtc < 0)
+ goto ack;
+
+ /* Nothing needs to be done for the encoder */
+ crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
+ if (crtc < 0)
+ goto ack;
+ /* Find which encoder was connected to the CRTC */
+ for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
+ mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
+ NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
+
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = OUTPUT_ANALOG; break;
+ case 1: type = OUTPUT_TV; break;
+ default:
+ NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
+ goto ack;
+ }
+
+ or = i;
+ }
+
+ for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+ if (dev_priv->chipset < 0x90 ||
+ dev_priv->chipset == 0x92 ||
+ dev_priv->chipset == 0xa0)
+ mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
+ else
+ mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
+
+ NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
+
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = OUTPUT_LVDS; break;
+ case 1: type = OUTPUT_TMDS; break;
+ case 2: type = OUTPUT_TMDS; break;
+ case 5: type = OUTPUT_TMDS; break;
+ case 8: type = OUTPUT_DP; break;
+ case 9: type = OUTPUT_DP; break;
+ default:
+ NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
+ goto ack;
+ }
+
+ or = i;
+ }
+
+ /* There was no encoder to disable */
+ if (type == OUTPUT_ANY)
+ goto ack;
+
+ /* Disable the encoder */
+ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
+ struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
+
+ if (dcb->type == type && (dcb->or & (1 << or))) {
+ nouveau_bios_run_display_table(dev, dcb, 0, -1);
+ dev_priv->evo_irq.dcb = dcb;
+ goto ack;
+ }
+ }
+
+ NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
ack:
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10);
nv_wr32(dev, 0x610030, 0x80000000);
@@ -817,33 +792,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
static void
nv50_display_unk20_handler(struct drm_device *dev)
{
- struct dcb_entry *dcbent;
- uint32_t tmp, pclk, script;
- int head, or, ret;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc;
+ struct dcb_entry *dcb;
+ int i, crtc, or, type = OUTPUT_ANY;
- ret = nv50_display_irq_head(dev, &head, &dcbent);
- if (ret)
+ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+ dcb = dev_priv->evo_irq.dcb;
+ if (dcb) {
+ nouveau_bios_run_display_table(dev, dcb, 0, -2);
+ dev_priv->evo_irq.dcb = NULL;
+ }
+
+ /* CRTC clock change requested? */
+ crtc = ffs((unk30 & 0x00000600) >> 9) - 1;
+ if (crtc >= 0) {
+ pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK));
+ pclk &= 0x003fffff;
+
+ nv50_crtc_set_clock(dev, crtc, pclk);
+
+ tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc));
+ tmp &= ~0x000000f;
+ nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp);
+ }
+
+ /* Nothing needs to be done for the encoder */
+ crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
+ if (crtc < 0)
goto ack;
- or = ffs(dcbent->or) - 1;
- pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
- script = nv50_display_script_select(dev, dcbent, pclk);
+ pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff;
- NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk);
+ /* Find which encoder is connected to the CRTC */
+ for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
+ mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i));
+ NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
- if (dcbent->type != OUTPUT_DP)
- nouveau_bios_run_display_table(dev, dcbent, 0, -2);
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = OUTPUT_ANALOG; break;
+ case 1: type = OUTPUT_TV; break;
+ default:
+ NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
+ goto ack;
+ }
- nv50_crtc_set_clock(dev, head, pclk);
+ or = i;
+ }
- nouveau_bios_run_display_table(dev, dcbent, script, pclk);
+ for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+ if (dev_priv->chipset < 0x90 ||
+ dev_priv->chipset == 0x92 ||
+ dev_priv->chipset == 0xa0)
+ mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i));
+ else
+ mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
- nv50_display_unk20_dp_hack(dev, dcbent);
+ NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
+
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = OUTPUT_LVDS; break;
+ case 1: type = OUTPUT_TMDS; break;
+ case 2: type = OUTPUT_TMDS; break;
+ case 5: type = OUTPUT_TMDS; break;
+ case 8: type = OUTPUT_DP; break;
+ case 9: type = OUTPUT_DP; break;
+ default:
+ NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
+ goto ack;
+ }
+
+ or = i;
+ }
+
+ if (type == OUTPUT_ANY)
+ goto ack;
+
+ /* Enable the encoder */
+ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
+ dcb = &dev_priv->vbios.dcb.entry[i];
+ if (dcb->type == type && (dcb->or & (1 << or)))
+ break;
+ }
+
+ if (i == dev_priv->vbios.dcb.entries) {
+ NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
+ goto ack;
+ }
- tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
- tmp &= ~0x000000f;
- nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp);
+ script = nv50_display_script_select(dev, dcb, mc, pclk);
+ nouveau_bios_run_display_table(dev, dcb, script, pclk);
- if (dcbent->type != OUTPUT_ANALOG) {
+ nv50_display_unk20_dp_hack(dev, dcb);
+
+ if (dcb->type != OUTPUT_ANALOG) {
tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
tmp &= ~0x00000f0f;
if (script & 0x0100)
@@ -853,24 +898,61 @@ nv50_display_unk20_handler(struct drm_device *dev)
nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
}
+ dev_priv->evo_irq.dcb = dcb;
+ dev_priv->evo_irq.pclk = pclk;
+ dev_priv->evo_irq.script = script;
+
ack:
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20);
nv_wr32(dev, 0x610030, 0x80000000);
}
+/* If programming a TMDS output on a SOR that can also be configured for
+ * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
+ *
+ * It looks like the VBIOS TMDS scripts make an attempt at this, however,
+ * the VBIOS scripts on at least one board I have only switch it off on
+ * link 0, causing a blank display if the output has previously been
+ * programmed for DisplayPort.
+ */
+static void
+nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb)
+{
+ int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
+ struct drm_encoder *encoder;
+ u32 tmp;
+
+ if (dcb->type != OUTPUT_TMDS)
+ return;
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+
+ if (nv_encoder->dcb->type == OUTPUT_DP &&
+ nv_encoder->dcb->or & (1 << or)) {
+ tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+ tmp &= ~NV50_SOR_DP_CTRL_ENABLED;
+ nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
+ break;
+ }
+ }
+}
+
static void
nv50_display_unk40_handler(struct drm_device *dev)
{
- struct dcb_entry *dcbent;
- int head, pclk, script, ret;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct dcb_entry *dcb = dev_priv->evo_irq.dcb;
+ u16 script = dev_priv->evo_irq.script;
+ u32 unk30 = nv_rd32(dev, 0x610030), pclk = dev_priv->evo_irq.pclk;
- ret = nv50_display_irq_head(dev, &head, &dcbent);
- if (ret)
+ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+ dev_priv->evo_irq.dcb = NULL;
+ if (!dcb)
goto ack;
- pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
- script = nv50_display_script_select(dev, dcbent, pclk);
- nouveau_bios_run_display_table(dev, dcbent, script, -pclk);
+ nouveau_bios_run_display_table(dev, dcb, script, -pclk);
+ nv50_display_unk40_dp_set_tmds(dev, dcb);
ack:
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40);
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index 581d405ac01..c551f0b85ee 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -38,9 +38,11 @@
void nv50_display_irq_handler(struct drm_device *dev);
void nv50_display_irq_handler_bh(struct work_struct *work);
void nv50_display_irq_hotplug_bh(struct work_struct *work);
-int nv50_display_init(struct drm_device *dev);
+int nv50_display_early_init(struct drm_device *dev);
+void nv50_display_late_takedown(struct drm_device *dev);
int nv50_display_create(struct drm_device *dev);
-int nv50_display_destroy(struct drm_device *dev);
+int nv50_display_init(struct drm_device *dev);
+void nv50_display_destroy(struct drm_device *dev);
int nv50_crtc_blank(struct nouveau_crtc *, bool blank);
int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
index e20c0e2474f..fb0281ae8f9 100644
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -28,41 +28,33 @@
#include "drm.h"
#include "nouveau_drv.h"
-struct nv50_fifo_priv {
- struct nouveau_gpuobj_ref *thingo[2];
- int cur_thingo;
-};
-
-#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
-
static void
-nv50_fifo_init_thingo(struct drm_device *dev)
+nv50_fifo_playlist_update(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_gpuobj_ref *cur;
int i, nr;
NV_DEBUG(dev, "\n");
- cur = priv->thingo[priv->cur_thingo];
- priv->cur_thingo = !priv->cur_thingo;
+ cur = pfifo->playlist[pfifo->cur_playlist];
+ pfifo->cur_playlist = !pfifo->cur_playlist;
/* We never schedule channel 0 or 127 */
- dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 1, nr = 0; i < 127; i++) {
if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc)
nv_wo32(dev, cur->gpuobj, nr++, i);
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
nv_wr32(dev, 0x32f4, cur->instance >> 12);
nv_wr32(dev, 0x32ec, nr);
nv_wr32(dev, 0x2500, 0x101);
}
-static int
-nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
+static void
+nv50_fifo_channel_enable(struct drm_device *dev, int channel)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->fifos[channel];
@@ -70,37 +62,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
NV_DEBUG(dev, "ch%d\n", channel);
- if (!chan->ramfc)
- return -EINVAL;
-
- if (IS_G80)
+ if (dev_priv->chipset == 0x50)
inst = chan->ramfc->instance >> 12;
else
inst = chan->ramfc->instance >> 8;
- nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel),
- inst | NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
- if (!nt)
- nv50_fifo_init_thingo(dev);
- return 0;
+ nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst |
+ NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
}
static void
-nv50_fifo_channel_disable(struct drm_device *dev, int channel, bool nt)
+nv50_fifo_channel_disable(struct drm_device *dev, int channel)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t inst;
- NV_DEBUG(dev, "ch%d, nt=%d\n", channel, nt);
+ NV_DEBUG(dev, "ch%d\n", channel);
- if (IS_G80)
+ if (dev_priv->chipset == 0x50)
inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80;
else
inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84;
nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst);
-
- if (!nt)
- nv50_fifo_init_thingo(dev);
}
static void
@@ -133,12 +116,12 @@ nv50_fifo_init_context_table(struct drm_device *dev)
for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) {
if (dev_priv->fifos[i])
- nv50_fifo_channel_enable(dev, i, true);
+ nv50_fifo_channel_enable(dev, i);
else
- nv50_fifo_channel_disable(dev, i, true);
+ nv50_fifo_channel_disable(dev, i);
}
- nv50_fifo_init_thingo(dev);
+ nv50_fifo_playlist_update(dev);
}
static void
@@ -162,41 +145,38 @@ nv50_fifo_init_regs(struct drm_device *dev)
nv_wr32(dev, 0x3270, 0);
/* Enable dummy channels setup by nv50_instmem.c */
- nv50_fifo_channel_enable(dev, 0, true);
- nv50_fifo_channel_enable(dev, 127, true);
+ nv50_fifo_channel_enable(dev, 0);
+ nv50_fifo_channel_enable(dev, 127);
}
int
nv50_fifo_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_fifo_priv *priv;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
int ret;
NV_DEBUG(dev, "\n");
- priv = dev_priv->engine.fifo.priv;
- if (priv) {
- priv->cur_thingo = !priv->cur_thingo;
+ if (pfifo->playlist[0]) {
+ pfifo->cur_playlist = !pfifo->cur_playlist;
goto just_reset;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- dev_priv->engine.fifo.priv = priv;
-
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[0]);
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &pfifo->playlist[0]);
if (ret) {
- NV_ERROR(dev, "error creating thingo0: %d\n", ret);
+ NV_ERROR(dev, "error creating playlist 0: %d\n", ret);
return ret;
}
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[1]);
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &pfifo->playlist[1]);
if (ret) {
- NV_ERROR(dev, "error creating thingo1: %d\n", ret);
+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
+ NV_ERROR(dev, "error creating playlist 1: %d\n", ret);
return ret;
}
@@ -216,18 +196,15 @@ void
nv50_fifo_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
NV_DEBUG(dev, "\n");
- if (!priv)
+ if (!pfifo->playlist[0])
return;
- nouveau_gpuobj_ref_del(dev, &priv->thingo[0]);
- nouveau_gpuobj_ref_del(dev, &priv->thingo[1]);
-
- dev_priv->engine.fifo.priv = NULL;
- kfree(priv);
+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]);
}
int
@@ -248,7 +225,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
- if (IS_G80) {
+ if (dev_priv->chipset == 0x50) {
uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start;
uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start;
@@ -281,10 +258,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- dev_priv->engine.instmem.prepare_access(dev, true);
-
nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
- nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4));
+ nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->instance >> 4));
nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
@@ -295,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
chan->dma.ib_base * 4);
nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
- if (!IS_G80) {
+ if (dev_priv->chipset != 0x50) {
nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);
nv_wo32(dev, chan->ramin->gpuobj, 1,
chan->ramfc->instance >> 8);
@@ -304,16 +281,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12);
}
- dev_priv->engine.instmem.finish_access(dev);
-
- ret = nv50_fifo_channel_enable(dev, chan->id, false);
- if (ret) {
- NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- nouveau_gpuobj_ref_del(dev, &chan->ramfc);
- return ret;
- }
+ dev_priv->engine.instmem.flush(dev);
+ nv50_fifo_channel_enable(dev, chan->id);
+ nv50_fifo_playlist_update(dev);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}
@@ -328,11 +299,12 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
/* This will ensure the channel is seen as disabled. */
chan->ramfc = NULL;
- nv50_fifo_channel_disable(dev, chan->id, false);
+ nv50_fifo_channel_disable(dev, chan->id);
/* Dummy channel, also used on ch 127 */
if (chan->id == 0)
- nv50_fifo_channel_disable(dev, 127, false);
+ nv50_fifo_channel_disable(dev, 127);
+ nv50_fifo_playlist_update(dev);
nouveau_gpuobj_ref_del(dev, &ramfc);
nouveau_gpuobj_ref_del(dev, &chan->cache);
@@ -349,8 +321,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
- dev_priv->engine.instmem.prepare_access(dev, false);
-
nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4));
nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4));
nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4));
@@ -396,7 +366,7 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
/* guessing that all the 0x34xx regs aren't on NV50 */
- if (!IS_G80) {
+ if (dev_priv->chipset != 0x50) {
nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4));
nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4));
nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4));
@@ -404,8 +374,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4));
}
- dev_priv->engine.instmem.finish_access(dev);
-
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16));
return 0;
}
@@ -434,8 +402,6 @@ nv50_fifo_unload_context(struct drm_device *dev)
ramfc = chan->ramfc->gpuobj;
cache = chan->cache->gpuobj;
- dev_priv->engine.instmem.prepare_access(dev, true);
-
nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330));
nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334));
nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240));
@@ -482,7 +448,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
}
/* guessing that all the 0x34xx regs aren't on NV50 */
- if (!IS_G80) {
+ if (dev_priv->chipset != 0x50) {
nv_wo32(dev, ramfc, 0x84/4, ptr >> 1);
nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c));
nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400));
@@ -491,7 +457,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410));
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
/*XXX: probably reload ch127 (NULL) state back too */
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, 127);
diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c
index bb47ad73726..b2fab2bf3d6 100644
--- a/drivers/gpu/drm/nouveau/nv50_gpio.c
+++ b/drivers/gpu/drm/nouveau/nv50_gpio.c
@@ -74,3 +74,38 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
nv_wr32(dev, r, v);
return 0;
}
+
+void
+nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on)
+{
+ struct dcb_gpio_entry *gpio;
+ u32 reg, mask;
+
+ gpio = nouveau_bios_gpio_entry(dev, tag);
+ if (!gpio) {
+ NV_ERROR(dev, "gpio tag 0x%02x not found\n", tag);
+ return;
+ }
+
+ reg = gpio->line < 16 ? 0xe050 : 0xe070;
+ mask = 0x00010001 << (gpio->line & 0xf);
+
+ nv_wr32(dev, reg + 4, mask);
+ nv_mask(dev, reg + 0, mask, on ? mask : 0);
+}
+
+int
+nv50_gpio_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ /* disable, and ack any pending gpio interrupts */
+ nv_wr32(dev, 0xe050, 0x00000000);
+ nv_wr32(dev, 0xe054, 0xffffffff);
+ if (dev_priv->chipset >= 0x90) {
+ nv_wr32(dev, 0xe070, 0x00000000);
+ nv_wr32(dev, 0xe074, 0xffffffff);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index b203d06f601..1413028e158 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -30,8 +30,6 @@
#include "nouveau_grctx.h"
-#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
-
static void
nv50_graph_init_reset(struct drm_device *dev)
{
@@ -103,37 +101,33 @@ static int
nv50_graph_init_ctxctl(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_grctx ctx = {};
+ uint32_t *cp;
+ int i;
NV_DEBUG(dev, "\n");
- if (nouveau_ctxfw) {
- nouveau_grctx_prog_load(dev);
- dev_priv->engine.graph.grctx_size = 0x70000;
+ cp = kmalloc(512 * 4, GFP_KERNEL);
+ if (!cp) {
+ NV_ERROR(dev, "failed to allocate ctxprog\n");
+ dev_priv->engine.graph.accel_blocked = true;
+ return 0;
}
- if (!dev_priv->engine.graph.ctxprog) {
- struct nouveau_grctx ctx = {};
- uint32_t *cp = kmalloc(512 * 4, GFP_KERNEL);
- int i;
- if (!cp) {
- NV_ERROR(dev, "Couldn't alloc ctxprog! Disabling acceleration.\n");
- dev_priv->engine.graph.accel_blocked = true;
- return 0;
- }
- ctx.dev = dev;
- ctx.mode = NOUVEAU_GRCTX_PROG;
- ctx.data = cp;
- ctx.ctxprog_max = 512;
- if (!nv50_grctx_init(&ctx)) {
- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
-
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
- for (i = 0; i < ctx.ctxprog_len; i++)
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
- } else {
- dev_priv->engine.graph.accel_blocked = true;
- }
- kfree(cp);
+
+ ctx.dev = dev;
+ ctx.mode = NOUVEAU_GRCTX_PROG;
+ ctx.data = cp;
+ ctx.ctxprog_max = 512;
+ if (!nv50_grctx_init(&ctx)) {
+ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < ctx.ctxprog_len; i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
+ } else {
+ dev_priv->engine.graph.accel_blocked = true;
}
+ kfree(cp);
nv_wr32(dev, 0x400320, 4);
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
@@ -164,7 +158,6 @@ void
nv50_graph_takedown(struct drm_device *dev)
{
NV_DEBUG(dev, "\n");
- nouveau_grctx_fini(dev);
}
void
@@ -212,8 +205,9 @@ nv50_graph_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
- struct nouveau_gpuobj *ctx;
+ struct nouveau_gpuobj *obj;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_grctx ctx = {};
int hdr, ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
@@ -223,10 +217,9 @@ nv50_graph_create_context(struct nouveau_channel *chan)
NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
if (ret)
return ret;
- ctx = chan->ramin_grctx->gpuobj;
+ obj = chan->ramin_grctx->gpuobj;
- hdr = IS_G80 ? 0x200 : 0x20;
- dev_priv->engine.instmem.prepare_access(dev, true);
+ hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
pgraph->grctx_size - 1);
@@ -234,21 +227,15 @@ nv50_graph_create_context(struct nouveau_channel *chan)
nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000);
- dev_priv->engine.instmem.finish_access(dev);
-
- dev_priv->engine.instmem.prepare_access(dev, true);
- if (!pgraph->ctxprog) {
- struct nouveau_grctx ctx = {};
- ctx.dev = chan->dev;
- ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = chan->ramin_grctx->gpuobj;
- nv50_grctx_init(&ctx);
- } else {
- nouveau_grctx_vals_load(dev, ctx);
- }
- nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
- dev_priv->engine.instmem.finish_access(dev);
+ ctx.dev = chan->dev;
+ ctx.mode = NOUVEAU_GRCTX_VALS;
+ ctx.data = obj;
+ nv50_grctx_init(&ctx);
+
+ nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12);
+
+ dev_priv->engine.instmem.flush(dev);
return 0;
}
@@ -257,17 +244,16 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int i, hdr = IS_G80 ? 0x200 : 0x20;
+ int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
NV_DEBUG(dev, "ch%d\n", chan->id);
if (!chan->ramin || !chan->ramin->gpuobj)
return;
- dev_priv->engine.instmem.prepare_access(dev, true);
for (i = hdr; i < hdr + 24; i += 4)
nv_wo32(dev, chan->ramin->gpuobj, i/4, 0);
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
}
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
index 5f21df31f3a..91ef93cf1f3 100644
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
@@ -35,8 +35,6 @@ struct nv50_instmem_priv {
struct nouveau_gpuobj_ref *pramin_pt;
struct nouveau_gpuobj_ref *pramin_bar;
struct nouveau_gpuobj_ref *fb_bar;
-
- bool last_access_wr;
};
#define NV50_INSTMEM_PAGE_SHIFT 12
@@ -141,13 +139,15 @@ nv50_instmem_init(struct drm_device *dev)
chan->file_priv = (struct drm_file *)-2;
dev_priv->fifos[0] = dev_priv->fifos[127] = chan;
+ INIT_LIST_HEAD(&chan->ramht_refs);
+
/* Channel's PRAMIN object + heap */
ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0,
NULL, &chan->ramin);
if (ret)
return ret;
- if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base))
+ if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base))
return -ENOMEM;
/* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
@@ -241,7 +241,7 @@ nv50_instmem_init(struct drm_device *dev)
return ret;
BAR0_WI32(priv->fb_bar->gpuobj, 0x00, 0x7fc00000);
BAR0_WI32(priv->fb_bar->gpuobj, 0x04, 0x40000000 +
- drm_get_resource_len(dev, 1) - 1);
+ pci_resource_len(dev->pdev, 1) - 1);
BAR0_WI32(priv->fb_bar->gpuobj, 0x08, 0x40000000);
BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000);
BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000);
@@ -262,30 +262,25 @@ nv50_instmem_init(struct drm_device *dev)
/* Assume that praying isn't enough, check that we can re-read the
* entire fake channel back from the PRAMIN BAR */
- dev_priv->engine.instmem.prepare_access(dev, false);
for (i = 0; i < c_size; i += 4) {
if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) {
NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n",
i);
- dev_priv->engine.instmem.finish_access(dev);
return -EINVAL;
}
}
- dev_priv->engine.instmem.finish_access(dev);
nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
/* Global PRAMIN heap */
- if (nouveau_mem_init_heap(&dev_priv->ramin_heap,
- c_size, dev_priv->ramin_size - c_size)) {
- dev_priv->ramin_heap = NULL;
+ if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) {
NV_ERROR(dev, "Failed to init RAMIN heap\n");
}
/*XXX: incorrect, but needed to make hash func "work" */
dev_priv->ramht_offset = 0x10000;
dev_priv->ramht_bits = 9;
- dev_priv->ramht_size = (1 << dev_priv->ramht_bits);
+ dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8;
return 0;
}
@@ -321,7 +316,7 @@ nv50_instmem_takedown(struct drm_device *dev)
nouveau_gpuobj_del(dev, &chan->vm_pd);
nouveau_gpuobj_ref_del(dev, &chan->ramfc);
nouveau_gpuobj_ref_del(dev, &chan->ramin);
- nouveau_mem_takedown(&chan->ramin_heap);
+ drm_mm_takedown(&chan->ramin_heap);
dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
kfree(chan);
@@ -436,14 +431,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
return -EINVAL;
- NV_DEBUG(dev, "st=0x%0llx sz=0x%0llx\n",
+ NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
gpuobj->im_pramin->start, gpuobj->im_pramin->size);
pte = (gpuobj->im_pramin->start >> 12) << 1;
pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
vram = gpuobj->im_backing_start;
- NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n",
+ NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
gpuobj->im_pramin->start, pte, pte_end);
NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
@@ -453,27 +448,15 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
vram |= 0x30;
}
- dev_priv->engine.instmem.prepare_access(dev, true);
while (pte < pte_end) {
nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
vram += NV50_INSTMEM_PAGE_SIZE;
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, 0x100c80, 0x00040001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (1)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00060001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
+ nv50_vm_flush(dev, 4);
+ nv50_vm_flush(dev, 6);
gpuobj->im_bound = 1;
return 0;
@@ -492,36 +475,37 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
pte = (gpuobj->im_pramin->start >> 12) << 1;
pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
- dev_priv->engine.instmem.prepare_access(dev, true);
while (pte < pte_end) {
nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
gpuobj->im_bound = 0;
return 0;
}
void
-nv50_instmem_prepare_access(struct drm_device *dev, bool write)
+nv50_instmem_flush(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
-
- priv->last_access_wr = write;
+ nv_wr32(dev, 0x00330c, 0x00000001);
+ if (!nv_wait(0x00330c, 0x00000002, 0x00000000))
+ NV_ERROR(dev, "PRAMIN flush timeout\n");
}
void
-nv50_instmem_finish_access(struct drm_device *dev)
+nv84_instmem_flush(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
+ nv_wr32(dev, 0x070000, 0x00000001);
+ if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+ NV_ERROR(dev, "PRAMIN flush timeout\n");
+}
- if (priv->last_access_wr) {
- nv_wr32(dev, 0x070000, 0x00000001);
- if (!nv_wait(0x070000, 0x00000001, 0x00000000))
- NV_ERROR(dev, "PRAMIN flush timeout\n");
- }
+void
+nv50_vm_flush(struct drm_device *dev, int engine)
+{
+ nv_wr32(dev, 0x100c80, (engine << 16) | 1);
+ if (!nv_wait(0x100c80, 0x00000001, 0x00000000))
+ NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
}
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index 812778db76a..bcd4cf84a7e 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -37,52 +37,32 @@
#include "nv50_display.h"
static void
-nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
+nv50_sor_disconnect(struct drm_encoder *encoder)
{
- struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
int ret;
+ if (!nv_encoder->crtc)
+ return;
+ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
+
NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
- ret = RING_SPACE(evo, 2);
+ ret = RING_SPACE(evo, 4);
if (ret) {
NV_ERROR(dev, "no space while disconnecting SOR\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
- OUT_RING(evo, 0);
-}
-
-static void
-nv50_sor_dp_link_train(struct drm_encoder *encoder)
-{
- struct drm_device *dev = encoder->dev;
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct bit_displayport_encoder_table *dpe;
- int dpe_headerlen;
-
- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
- if (!dpe) {
- NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or);
- return;
- }
+ OUT_RING (evo, 0);
+ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING (evo, 0);
- if (dpe->script0) {
- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
- nv_encoder->dcb);
- }
-
- if (!nouveau_dp_link_train(encoder))
- NV_ERROR(dev, "SOR-%d: link training failed\n", nv_encoder->or);
-
- if (dpe->script1) {
- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
- nv_encoder->dcb);
- }
+ nv_encoder->crtc = NULL;
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
}
static void
@@ -94,14 +74,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
uint32_t val;
int or = nv_encoder->or;
- NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
+ NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode);
nv_encoder->last_dpms = mode;
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nvenc = nouveau_encoder(enc);
if (nvenc == nv_encoder ||
- nvenc->disconnect != nv50_sor_disconnect ||
+ (nvenc->dcb->type != OUTPUT_TMDS &&
+ nvenc->dcb->type != OUTPUT_LVDS &&
+ nvenc->dcb->type != OUTPUT_DP) ||
nvenc->dcb->or != nv_encoder->dcb->or)
continue;
@@ -133,8 +115,22 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or)));
}
- if (nv_encoder->dcb->type == OUTPUT_DP && mode == DRM_MODE_DPMS_ON)
- nv50_sor_dp_link_train(encoder);
+ if (nv_encoder->dcb->type == OUTPUT_DP) {
+ struct nouveau_i2c_chan *auxch;
+
+ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
+ if (!auxch)
+ return;
+
+ if (mode == DRM_MODE_DPMS_ON) {
+ u8 status = DP_SET_POWER_D0;
+ nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+ nouveau_dp_link_train(encoder);
+ } else {
+ u8 status = DP_SET_POWER_D3;
+ nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+ }
+ }
}
static void
@@ -196,7 +192,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
uint32_t mode_ctl = 0;
int ret;
- NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n",
+ nv_encoder->or, nv_encoder->dcb->type, crtc->index);
nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
@@ -239,6 +236,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
OUT_RING(evo, mode_ctl);
+
+ nv_encoder->crtc = encoder->crtc;
+}
+
+static struct drm_crtc *
+nv50_sor_crtc_get(struct drm_encoder *encoder)
+{
+ return nouveau_encoder(encoder)->crtc;
}
static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
@@ -249,7 +254,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
.prepare = nv50_sor_prepare,
.commit = nv50_sor_commit,
.mode_set = nv50_sor_mode_set,
- .detect = NULL
+ .get_crtc = nv50_sor_crtc_get,
+ .detect = NULL,
+ .disable = nv50_sor_disconnect
};
static void
@@ -272,32 +279,22 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = {
};
int
-nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
+nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
{
struct nouveau_encoder *nv_encoder = NULL;
+ struct drm_device *dev = connector->dev;
struct drm_encoder *encoder;
- bool dum;
int type;
NV_DEBUG_KMS(dev, "\n");
switch (entry->type) {
case OUTPUT_TMDS:
- NV_INFO(dev, "Detected a TMDS output\n");
+ case OUTPUT_DP:
type = DRM_MODE_ENCODER_TMDS;
break;
case OUTPUT_LVDS:
- NV_INFO(dev, "Detected a LVDS output\n");
type = DRM_MODE_ENCODER_LVDS;
-
- if (nouveau_bios_parse_lvds_table(dev, 0, &dum, &dum)) {
- NV_ERROR(dev, "Failed parsing LVDS table\n");
- return -EINVAL;
- }
- break;
- case OUTPUT_DP:
- NV_INFO(dev, "Detected a DP output\n");
- type = DRM_MODE_ENCODER_TMDS;
break;
default:
return -EINVAL;
@@ -310,8 +307,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
-
- nv_encoder->disconnect = nv50_sor_disconnect;
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type);
drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);
@@ -342,5 +338,6 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dp.mc_unknown = 5;
}
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c
new file mode 100644
index 00000000000..26a996025dd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_fb.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+int
+nvc0_fb_init(struct drm_device *dev)
+{
+ return 0;
+}
+
+void
+nvc0_fb_takedown(struct drm_device *dev)
+{
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
new file mode 100644
index 00000000000..d6437587197
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+void
+nvc0_fifo_disable(struct drm_device *dev)
+{
+}
+
+void
+nvc0_fifo_enable(struct drm_device *dev)
+{
+}
+
+bool
+nvc0_fifo_reassign(struct drm_device *dev, bool enable)
+{
+ return false;
+}
+
+bool
+nvc0_fifo_cache_flush(struct drm_device *dev)
+{
+ return true;
+}
+
+bool
+nvc0_fifo_cache_pull(struct drm_device *dev, bool enable)
+{
+ return false;
+}
+
+int
+nvc0_fifo_channel_id(struct drm_device *dev)
+{
+ return 127;
+}
+
+int
+nvc0_fifo_create_context(struct nouveau_channel *chan)
+{
+ return 0;
+}
+
+void
+nvc0_fifo_destroy_context(struct nouveau_channel *chan)
+{
+}
+
+int
+nvc0_fifo_load_context(struct nouveau_channel *chan)
+{
+ return 0;
+}
+
+int
+nvc0_fifo_unload_context(struct drm_device *dev)
+{
+ return 0;
+}
+
+void
+nvc0_fifo_takedown(struct drm_device *dev)
+{
+}
+
+int
+nvc0_fifo_init(struct drm_device *dev)
+{
+ return 0;
+}
+
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
new file mode 100644
index 00000000000..717a5177a8d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+void
+nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
+{
+}
+
+struct nouveau_channel *
+nvc0_graph_channel(struct drm_device *dev)
+{
+ return NULL;
+}
+
+int
+nvc0_graph_create_context(struct nouveau_channel *chan)
+{
+ return 0;
+}
+
+void
+nvc0_graph_destroy_context(struct nouveau_channel *chan)
+{
+}
+
+int
+nvc0_graph_load_context(struct nouveau_channel *chan)
+{
+ return 0;
+}
+
+int
+nvc0_graph_unload_context(struct drm_device *dev)
+{
+ return 0;
+}
+
+void
+nvc0_graph_takedown(struct drm_device *dev)
+{
+}
+
+int
+nvc0_graph_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ dev_priv->engine.graph.accel_blocked = true;
+ return 0;
+}
+
diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c
new file mode 100644
index 00000000000..6b451f86478
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+int
+nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+ uint32_t *size)
+{
+ int ret;
+
+ *size = ALIGN(*size, 4096);
+ if (*size == 0)
+ return -EINVAL;
+
+ ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000,
+ true, false, &gpuobj->im_backing);
+ if (ret) {
+ NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret);
+ return ret;
+ }
+
+ ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM);
+ if (ret) {
+ NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret);
+ nouveau_bo_ref(NULL, &gpuobj->im_backing);
+ return ret;
+ }
+
+ gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
+ gpuobj->im_backing_start <<= PAGE_SHIFT;
+ return 0;
+}
+
+void
+nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (gpuobj && gpuobj->im_backing) {
+ if (gpuobj->im_bound)
+ dev_priv->engine.instmem.unbind(dev, gpuobj);
+ nouveau_bo_unpin(gpuobj->im_backing);
+ nouveau_bo_ref(NULL, &gpuobj->im_backing);
+ gpuobj->im_backing = NULL;
+ }
+}
+
+int
+nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ uint32_t pte, pte_end;
+ uint64_t vram;
+
+ if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
+ return -EINVAL;
+
+ NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
+ gpuobj->im_pramin->start, gpuobj->im_pramin->size);
+
+ pte = gpuobj->im_pramin->start >> 12;
+ pte_end = (gpuobj->im_pramin->size >> 12) + pte;
+ vram = gpuobj->im_backing_start;
+
+ NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
+ gpuobj->im_pramin->start, pte, pte_end);
+ NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+
+ while (pte < pte_end) {
+ nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1);
+ nv_wr32(dev, 0x702004 + (pte * 8), 0);
+ vram += 4096;
+ pte++;
+ }
+ dev_priv->engine.instmem.flush(dev);
+
+ if (1) {
+ u32 chan = nv_rd32(dev, 0x1700) << 16;
+ nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8);
+ nv_wr32(dev, 0x100cbc, 0x80000005);
+ }
+
+ gpuobj->im_bound = 1;
+ return 0;
+}
+
+int
+nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ uint32_t pte, pte_end;
+
+ if (gpuobj->im_bound == 0)
+ return -EINVAL;
+
+ pte = gpuobj->im_pramin->start >> 12;
+ pte_end = (gpuobj->im_pramin->size >> 12) + pte;
+ while (pte < pte_end) {
+ nv_wr32(dev, 0x702000 + (pte * 8), 0);
+ nv_wr32(dev, 0x702004 + (pte * 8), 0);
+ pte++;
+ }
+ dev_priv->engine.instmem.flush(dev);
+
+ gpuobj->im_bound = 0;
+ return 0;
+}
+
+void
+nvc0_instmem_flush(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x070000, 1);
+ if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+ NV_ERROR(dev, "PRAMIN flush timeout\n");
+}
+
+int
+nvc0_instmem_suspend(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 *buf;
+ int i;
+
+ dev_priv->susres.ramin_copy = vmalloc(65536);
+ if (!dev_priv->susres.ramin_copy)
+ return -ENOMEM;
+ buf = dev_priv->susres.ramin_copy;
+
+ for (i = 0; i < 65536; i += 4)
+ buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i);
+ return 0;
+}
+
+void
+nvc0_instmem_resume(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 *buf = dev_priv->susres.ramin_copy;
+ u64 chan;
+ int i;
+
+ chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
+ nv_wr32(dev, 0x001700, chan >> 16);
+
+ for (i = 0; i < 65536; i += 4)
+ nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]);
+ vfree(dev_priv->susres.ramin_copy);
+ dev_priv->susres.ramin_copy = NULL;
+
+ nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
+}
+
+int
+nvc0_instmem_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1;
+ int ret, i;
+
+ dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024;
+ chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
+ imem = 4096 + 4096 + 32768;
+
+ nv_wr32(dev, 0x001700, chan >> 16);
+
+ /* channel setup */
+ nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000));
+ nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000));
+ nv_wr32(dev, 0x700208, lower_32_bits(lim3));
+ nv_wr32(dev, 0x70020c, upper_32_bits(lim3));
+
+ /* point pgd -> pgt */
+ nv_wr32(dev, 0x701000, 0);
+ nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1);
+
+ /* point pgt -> physical vram for channel */
+ pgt3 = 0x2000;
+ for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) {
+ nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1);
+ nv_wr32(dev, 0x700004 + pgt3, 0);
+ }
+
+ /* clear rest of pgt */
+ for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) {
+ nv_wr32(dev, 0x700000 + pgt3, 0);
+ nv_wr32(dev, 0x700004 + pgt3, 0);
+ }
+
+ /* point bar3 at the channel */
+ nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
+
+ /* Global PRAMIN heap */
+ ret = drm_mm_init(&dev_priv->ramin_heap, imem,
+ dev_priv->ramin_size - imem);
+ if (ret) {
+ NV_ERROR(dev, "Failed to init RAMIN heap\n");
+ return -ENOMEM;
+ }
+
+ /*XXX: incorrect, but needed to make hash func "work" */
+ dev_priv->ramht_offset = 0x10000;
+ dev_priv->ramht_bits = 9;
+ dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8;
+ return 0;
+}
+
+void
+nvc0_instmem_takedown(struct drm_device *dev)
+{
+}
+
diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h
index 5998c35237b..ad64673ace1 100644
--- a/drivers/gpu/drm/nouveau/nvreg.h
+++ b/drivers/gpu/drm/nouveau/nvreg.h
@@ -147,28 +147,6 @@
# define NV_VIO_GX_DONT_CARE_INDEX 0x07
# define NV_VIO_GX_BIT_MASK_INDEX 0x08
-#define NV_PFB_BOOT_0 0x00100000
-#define NV_PFB_CFG0 0x00100200
-#define NV_PFB_CFG1 0x00100204
-#define NV_PFB_CSTATUS 0x0010020C
-#define NV_PFB_REFCTRL 0x00100210
-# define NV_PFB_REFCTRL_VALID_1 (1 << 31)
-#define NV_PFB_PAD 0x0010021C
-# define NV_PFB_PAD_CKE_NORMAL (1 << 0)
-#define NV_PFB_TILE_NV10 0x00100240
-#define NV_PFB_TILE_SIZE_NV10 0x00100244
-#define NV_PFB_REF 0x001002D0
-# define NV_PFB_REF_CMD_REFRESH (1 << 0)
-#define NV_PFB_PRE 0x001002D4
-# define NV_PFB_PRE_CMD_PRECHARGE (1 << 0)
-#define NV_PFB_CLOSE_PAGE2 0x0010033C
-#define NV_PFB_TILE_NV40 0x00100600
-#define NV_PFB_TILE_SIZE_NV40 0x00100604
-
-#define NV_PEXTDEV_BOOT_0 0x00101000
-# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12)
-#define NV_PEXTDEV_BOOT_3 0x0010100c
-
#define NV_PCRTC_INTR_0 0x00600100
# define NV_PCRTC_INTR_0_VBLANK (1 << 0)
#define NV_PCRTC_INTR_EN_0 0x00600140