diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau')
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 |