6054 lines
190 KiB
Diff
6054 lines
190 KiB
Diff
From 0c03c9751600b40a7c60e525135c75a7ab25a923 Mon Sep 17 00:00:00 2001
|
|
From: Ben Skeggs <bskeggs@redhat.com>
|
|
Date: Mon, 31 May 2010 12:00:43 +1000
|
|
Subject: [PATCH] drm-nouveau-updates
|
|
|
|
drm/nouveau: reduce usage of fence spinlock to when absolutely necessary
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: place notifiers in system memory by default
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: move LVDS detection back to connector detect() time
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: use drm_mm in preference to custom code doing the same thing
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: remove left-over !DRIVER_MODESET paths
|
|
|
|
It's far preferable to have the driver do nothing at all for "nomodeset".
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: missed some braces
|
|
|
|
Luckily this had absolutely no effect whatsoever :)
|
|
|
|
Reported-by: Marcin Slusarz <marcin.slusarz@gmail.com>
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: fix memory detection for cards with >=4GiB VRAM
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: Put the dithering check back in nouveau_connector_create.
|
|
|
|
a7b9f9e5adef dropped it by accident.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
Tested-by: Thibaut Girka <thib@sitedethib.com>
|
|
|
|
drm/nouveau: Don't clear AGPCMD completely on INIT_RESET.
|
|
|
|
We just need to clear the SBA and ENABLE bits to reset the AGP
|
|
controller: If the AGP bridge was configured to use "fast writes",
|
|
clearing the FW bit would break the subsequent MMIO writes and
|
|
eventually end with a lockup.
|
|
|
|
Note that all the BIOSes I've seen do the same as we did (it works for
|
|
them because they don't use MMIO), OTOH the blob leaves FW untouched.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nouveau: Ignore broken legacy I2C entries.
|
|
|
|
The nv05 card in the bug report [1] doesn't have usable I2C port
|
|
register offsets (they're all filled with zeros). Ignore them and use
|
|
the defaults.
|
|
|
|
[1] http://bugs.launchpad.net/bugs/569505
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nouveau: set encoder for lvds
|
|
|
|
fixes oops in nouveau_connector_get_modes with nv_encoder is NULL
|
|
|
|
Signed-off-by: Albert Damen <albrt@gmx.net>
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nouveau: tidy connector/encoder creation a little
|
|
|
|
Create connectors before encoders to avoid having to do another loop across
|
|
encoder list whenever we create a new connector. This allows us to pass
|
|
the connector to the encoder creation functions, and avoid using a
|
|
create_resources() callback since we can now call it directly.
|
|
|
|
This can also potentially modify the connector ordering on nv50. On cards
|
|
where the DCB connector and encoder tables are in the same order, things
|
|
will be unchanged. However, there's some cards where the ordering between
|
|
the tables differ, and in one case, leads us to naming the connectors
|
|
"wrongly".
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: downgrade severity of most init table parser errors
|
|
|
|
As long as we know the length of the opcode, we're probably better off
|
|
trying to parse the remainder of an init table rather than aborting in
|
|
the middle of it.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: fix DP->DVI if output has been programmed for native DP previously
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: DCB quirk for Dell M6300
|
|
|
|
Uncertain if this is a weirdo configuration, or a BIOS bug. If it's not
|
|
a BIOS bug, we still don't know how to make it work anyway so ignore a
|
|
"conflicting" DCB entry to prevent a display hang.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: supply encoder disable() hook for SOR outputs
|
|
|
|
Allows us to remove a driver hack that used to be necessary to disable
|
|
encoders in certain situations before setting up a mode. The DRM has
|
|
better knowledge of when this is needed than the driver does.
|
|
|
|
This fixes a number of display switching issues.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: fix regression caused by ed15e77b6ee7c4fa6f50c18b3325e7f96ed3aade
|
|
|
|
It became possible for us to have connectors present without any encoders
|
|
attached (TV out, we don't support TVDAC yet), which caused the DDX to
|
|
segfault.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv04: fix regression caused by ed15e77b6ee7c4fa6f50c18b3325e7f96ed3aade
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: when debugging on, log which crtc we connect an encoder to
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv17-nv40: Avoid using active CRTCs for load detection.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nv04-nv40: Prevent invalid DAC/TVDAC combinations.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nouveau: Fix a couple of sparse warnings.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nouveau: INIT_CONFIGURE_PREINIT/CLK/MEM on newer BIOSes is not an error.
|
|
|
|
No need to spam the logs when they're found, they're equivalent to
|
|
INIT_DONE.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nv04-nv40: Drop redundant logging.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nouveau: Move the fence wait before migration resource clean-up.
|
|
|
|
Avoids an oops in the fence wait failure path (bug 26521).
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
Tested-by: Marcin Slusarz <marcin.slusarz@gmail.com>
|
|
|
|
drm/nouveau: Workaround broken TV load detection on a "Zotac FX5200".
|
|
|
|
The blob seems to have the same problem so it's probably a hardware
|
|
issue (bug 28810).
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nv50: send evo "update" command after each disconnect
|
|
|
|
It turns out that the display engine signals an interrupt for disconnects
|
|
too. In order to make it easier to process the display interrupts
|
|
correctly, we want to ensure we only get one operation per interrupt
|
|
sequence - this is what this commit achieves.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: rewrite display irq handler
|
|
|
|
The previous handler basically worked correctly for a full-blown mode
|
|
change. However, it did nothing at all when a partial (encoder only)
|
|
reconfiguation was necessary, leading to the display hanging on certain
|
|
types of mode switch.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: move DP script invocation to nouveau_dp.c
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: set DP display power state during DPMS
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: add scaler-only modes for eDP too
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: remove dev_priv->init_state and friends
|
|
|
|
Nouveau will no longer load at all if card initialisation fails, so all
|
|
these checks are unnecessary.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: implement DAC disconnect fix missed in earlier commit
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: add instmem flush() hook
|
|
|
|
This removes the previous prepare_access() and finish_access() hooks, and
|
|
replaces it with a much simpler flush() hook.
|
|
|
|
All the chipset-specific code before nv50 has its use removed completely,
|
|
as it's not required there at all.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: move tlb flushing to a helper function
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: remove ability to use external firmware
|
|
|
|
This was always really a developer option, and if it's really necessary we
|
|
can hack this in ourselves.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: allocate fixed amount of PRAMIN per channel on all chipsets
|
|
|
|
Previously only done on nv50+
|
|
|
|
This commit also switches unknown NV2x/NV3x chipsets to noaccel mode.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: remove unused fbdev_info
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: cleanup nv50_fifo.c
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv20-nv30: move context table object out of dev_priv
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: fix dp_set_tmds to work on the right OR
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: fix mtrr cleanup path
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: move dp_set_tmds() function to happen in the last display irq
|
|
|
|
It seems on some chipsets that doing this from the 0x20 handler causes the
|
|
display engine to not ever signal the final 0x40 stage.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: initialise display before enabling interrupts
|
|
|
|
In some situations it's possible we can receive a spurious hotplug IRQ
|
|
before we're ready to handle it, leading to an oops.
|
|
|
|
Calling the display init before enabling interrupts should clear any
|
|
pending IRQs on the GPU and prevent this from happening.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: Fix crashes during fbcon init on single head cards.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nouveau: Disable PROM access on init.
|
|
|
|
On older cards (<nv17) scanout gets blocked when the ROM is being
|
|
accessed. PROM access usually comes out enabled from suspend, switch
|
|
it off.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nv04: Enable context switching on PFIFO init.
|
|
|
|
Fixes a lockup when coming back from suspend.
|
|
|
|
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
|
|
|
|
drm/nouveau: fix pcirom vbios shadow breakage from acpi rom patch
|
|
|
|
On nv50 it became impossible to attempt a PCI ROM shadow of the VBIOS,
|
|
which will break some setups.
|
|
|
|
This patch also removes the different ordering of shadow methods for
|
|
pre-nv50 chipsets. The reason for the different ordering was paranoia,
|
|
but it should hopefully be OK to try shadowing PRAMIN first.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: fix RAMHT size
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: remove quirk to fabricate DVI-A output on DCB 1.5 boards
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: support fetching LVDS EDID from ACPI
|
|
|
|
Based on a patch from Matthew Garrett.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: fix regression that break LVDS in some places
|
|
|
|
A previous commit started additionally using the SOR link when trying to
|
|
match the correct output script. However, we never fill in this field
|
|
for LVDS so we can never match a script at all.
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: add nv_mask register accessor
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nv50: add function to control GPIO IRQ reporting
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
|
|
drm/nouveau: disable hotplug detect around DP link training
|
|
|
|
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
|
|
---
|
|
drivers/gpu/drm/nouveau/Makefile | 2 +-
|
|
drivers/gpu/drm/nouveau/nouveau_acpi.c | 38 +++-
|
|
drivers/gpu/drm/nouveau/nouveau_bios.c | 206 ++++++++------
|
|
drivers/gpu/drm/nouveau/nouveau_bios.h | 2 +
|
|
drivers/gpu/drm/nouveau/nouveau_bo.c | 9 +-
|
|
drivers/gpu/drm/nouveau/nouveau_channel.c | 5 -
|
|
drivers/gpu/drm/nouveau/nouveau_connector.c | 281 +++++++++----------
|
|
drivers/gpu/drm/nouveau/nouveau_connector.h | 4 +-
|
|
drivers/gpu/drm/nouveau/nouveau_dma.c | 8 +-
|
|
drivers/gpu/drm/nouveau/nouveau_dp.c | 39 +++-
|
|
drivers/gpu/drm/nouveau/nouveau_drv.c | 26 +--
|
|
drivers/gpu/drm/nouveau/nouveau_drv.h | 98 +++----
|
|
drivers/gpu/drm/nouveau/nouveau_encoder.h | 10 +-
|
|
drivers/gpu/drm/nouveau/nouveau_fbcon.c | 5 +-
|
|
drivers/gpu/drm/nouveau/nouveau_fence.c | 31 +--
|
|
drivers/gpu/drm/nouveau/nouveau_gem.c | 11 +-
|
|
drivers/gpu/drm/nouveau/nouveau_grctx.c | 160 -----------
|
|
drivers/gpu/drm/nouveau/nouveau_mem.c | 261 ++----------------
|
|
drivers/gpu/drm/nouveau/nouveau_notifier.c | 30 +--
|
|
drivers/gpu/drm/nouveau/nouveau_object.c | 105 ++-----
|
|
drivers/gpu/drm/nouveau/nouveau_reg.h | 1 +
|
|
drivers/gpu/drm/nouveau/nouveau_sgdma.c | 46 +---
|
|
drivers/gpu/drm/nouveau/nouveau_state.c | 172 ++++--------
|
|
drivers/gpu/drm/nouveau/nv04_dac.c | 37 ++-
|
|
drivers/gpu/drm/nouveau/nv04_dfp.c | 12 +-
|
|
drivers/gpu/drm/nouveau/nv04_display.c | 23 ++-
|
|
drivers/gpu/drm/nouveau/nv04_fifo.c | 20 +-
|
|
drivers/gpu/drm/nouveau/nv04_graph.c | 5 +-
|
|
drivers/gpu/drm/nouveau/nv04_instmem.c | 21 +-
|
|
drivers/gpu/drm/nouveau/nv04_mc.c | 4 +
|
|
drivers/gpu/drm/nouveau/nv04_tv.c | 8 +-
|
|
drivers/gpu/drm/nouveau/nv10_fifo.c | 10 -
|
|
drivers/gpu/drm/nouveau/nv17_tv.c | 45 +++-
|
|
drivers/gpu/drm/nouveau/nv20_graph.c | 96 ++++---
|
|
drivers/gpu/drm/nouveau/nv40_fifo.c | 8 -
|
|
drivers/gpu/drm/nouveau/nv40_graph.c | 58 ++---
|
|
drivers/gpu/drm/nouveau/nv50_crtc.c | 42 +---
|
|
drivers/gpu/drm/nouveau/nv50_dac.c | 43 ++-
|
|
drivers/gpu/drm/nouveau/nv50_display.c | 405 ++++++++++++++++-----------
|
|
drivers/gpu/drm/nouveau/nv50_fifo.c | 126 +++------
|
|
drivers/gpu/drm/nouveau/nv50_gpio.c | 19 ++
|
|
drivers/gpu/drm/nouveau/nv50_graph.c | 86 +++----
|
|
drivers/gpu/drm/nouveau/nv50_instmem.c | 61 ++---
|
|
drivers/gpu/drm/nouveau/nv50_mc.c | 13 +
|
|
drivers/gpu/drm/nouveau/nv50_sor.c | 105 ++++----
|
|
45 files changed, 1181 insertions(+), 1616 deletions(-)
|
|
delete mode 100644 drivers/gpu/drm/nouveau/nouveau_grctx.c
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
|
|
index acd31ed..4a1db73 100644
|
|
--- a/drivers/gpu/drm/nouveau/Makefile
|
|
+++ b/drivers/gpu/drm/nouveau/Makefile
|
|
@@ -9,7 +9,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
|
|
nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
|
|
nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
|
|
nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
|
|
- nouveau_dp.o nouveau_grctx.o \
|
|
+ nouveau_dp.o \
|
|
nv04_timer.o \
|
|
nv04_mc.o nv40_mc.o nv50_mc.o \
|
|
nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
|
|
index d4bcca8..c17a055 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
|
|
@@ -3,6 +3,7 @@
|
|
#include <linux/slab.h>
|
|
#include <acpi/acpi_drivers.h>
|
|
#include <acpi/acpi_bus.h>
|
|
+#include <acpi/video.h>
|
|
|
|
#include "drmP.h"
|
|
#include "drm.h"
|
|
@@ -11,6 +12,7 @@
|
|
#include "nouveau_drv.h"
|
|
#include "nouveau_drm.h"
|
|
#include "nv50_display.h"
|
|
+#include "nouveau_connector.h"
|
|
|
|
#include <linux/vga_switcheroo.h>
|
|
|
|
@@ -42,7 +44,7 @@ static const char nouveau_dsm_muid[] = {
|
|
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
|
|
};
|
|
|
|
-static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result)
|
|
+static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
|
|
{
|
|
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
struct acpi_object_list input;
|
|
@@ -259,3 +261,37 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
|
|
{
|
|
return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
|
|
}
|
|
+
|
|
+int
|
|
+nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
|
|
+{
|
|
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
|
+ struct acpi_device *acpidev;
|
|
+ acpi_handle handle;
|
|
+ int type, ret;
|
|
+ void *edid;
|
|
+
|
|
+ switch (connector->connector_type) {
|
|
+ case DRM_MODE_CONNECTOR_LVDS:
|
|
+ case DRM_MODE_CONNECTOR_eDP:
|
|
+ type = ACPI_VIDEO_DISPLAY_LCD;
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
|
|
+ if (!handle)
|
|
+ return -ENODEV;
|
|
+
|
|
+ ret = acpi_bus_get_device(handle, &acpidev);
|
|
+ if (ret)
|
|
+ return -ENODEV;
|
|
+
|
|
+ ret = acpi_video_get_edid(acpidev, type, -1, &edid);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ nv_connector->edid = edid;
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
|
|
index fc924b6..0eb1b5a 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
|
|
@@ -203,36 +203,26 @@ struct methods {
|
|
const bool rw;
|
|
};
|
|
|
|
-static struct methods nv04_methods[] = {
|
|
- { "PROM", load_vbios_prom, false },
|
|
- { "PRAMIN", load_vbios_pramin, true },
|
|
- { "PCIROM", load_vbios_pci, true },
|
|
-};
|
|
-
|
|
-static struct methods nv50_methods[] = {
|
|
- { "ACPI", load_vbios_acpi, true },
|
|
+static struct methods shadow_methods[] = {
|
|
{ "PRAMIN", load_vbios_pramin, true },
|
|
{ "PROM", load_vbios_prom, false },
|
|
{ "PCIROM", load_vbios_pci, true },
|
|
+ { "ACPI", load_vbios_acpi, true },
|
|
};
|
|
|
|
-#define METHODCNT 3
|
|
-
|
|
static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
|
|
{
|
|
- struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- struct methods *methods;
|
|
- int i;
|
|
+ const int nr_methods = ARRAY_SIZE(shadow_methods);
|
|
+ struct methods *methods = shadow_methods;
|
|
int testscore = 3;
|
|
- int scores[METHODCNT];
|
|
+ int scores[nr_methods], i;
|
|
|
|
if (nouveau_vbios) {
|
|
- methods = nv04_methods;
|
|
- for (i = 0; i < METHODCNT; i++)
|
|
+ for (i = 0; i < nr_methods; i++)
|
|
if (!strcasecmp(nouveau_vbios, methods[i].desc))
|
|
break;
|
|
|
|
- if (i < METHODCNT) {
|
|
+ if (i < nr_methods) {
|
|
NV_INFO(dev, "Attempting to use BIOS image from %s\n",
|
|
methods[i].desc);
|
|
|
|
@@ -244,12 +234,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
|
|
NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
|
|
}
|
|
|
|
- if (dev_priv->card_type < NV_50)
|
|
- methods = nv04_methods;
|
|
- else
|
|
- methods = nv50_methods;
|
|
-
|
|
- for (i = 0; i < METHODCNT; i++) {
|
|
+ for (i = 0; i < nr_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 */
|
|
@@ -260,7 +245,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
|
|
}
|
|
|
|
while (--testscore > 0) {
|
|
- for (i = 0; i < METHODCNT; i++) {
|
|
+ for (i = 0; i < nr_methods; i++) {
|
|
if (scores[i] == testscore) {
|
|
NV_TRACE(dev, "Using BIOS image from %s\n",
|
|
methods[i].desc);
|
|
@@ -935,7 +920,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]);
|
|
@@ -1037,7 +1022,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]);
|
|
@@ -1209,7 +1194,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) {
|
|
@@ -1233,12 +1218,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;
|
|
@@ -1407,7 +1396,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]);
|
|
@@ -1467,6 +1456,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];
|
|
@@ -1481,9 +1471,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];
|
|
@@ -1494,8 +1486,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",
|
|
@@ -1509,8 +1503,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;
|
|
@@ -1535,6 +1531,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];
|
|
@@ -1549,9 +1546,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];
|
|
@@ -1568,8 +1567,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;
|
|
@@ -1592,6 +1593,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];
|
|
@@ -1599,7 +1601,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;
|
|
@@ -1608,9 +1610,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];
|
|
@@ -1623,8 +1627,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;
|
|
@@ -1648,6 +1655,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];
|
|
@@ -1662,8 +1670,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);
|
|
@@ -1693,6 +1703,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;
|
|
@@ -1706,8 +1717,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];
|
|
@@ -2146,7 +2159,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);
|
|
@@ -2182,7 +2196,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);
|
|
@@ -2237,7 +2251,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);
|
|
@@ -2270,7 +2284,7 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset,
|
|
uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6));
|
|
|
|
if (bios->major_version > 2)
|
|
- return -ENODEV;
|
|
+ return 0;
|
|
|
|
bios_idxprt_wr(bios, NV_CIO_CRX__COLOR,
|
|
NV_CIO_CRE_SCRATCH4__INDEX, cr3c);
|
|
@@ -2815,7 +2829,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
|
|
|
if (dev_priv->card_type != NV_50) {
|
|
NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
|
|
- return -ENODEV;
|
|
+ return 1;
|
|
}
|
|
|
|
if (!iexec->execute)
|
|
@@ -2887,10 +2901,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 "
|
|
@@ -2898,6 +2909,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];
|
|
|
|
@@ -3079,14 +3093,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)
|
|
@@ -3099,7 +3113,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];
|
|
@@ -3108,7 +3122,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;
|
|
}
|
|
}
|
|
|
|
@@ -3138,14 +3152,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)
|
|
@@ -3156,7 +3170,7 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
|
|
ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1);
|
|
if (ret) {
|
|
NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret);
|
|
- return ret;
|
|
+ return len;
|
|
}
|
|
}
|
|
|
|
@@ -5166,10 +5180,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]);
|
|
@@ -5604,9 +5622,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) {
|
|
/*
|
|
@@ -5721,13 +5742,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;
|
|
@@ -5808,6 +5822,31 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb)
|
|
dcb->entries = newentries;
|
|
}
|
|
|
|
+static bool
|
|
+apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
|
|
+{
|
|
+ /* Dell Precision M6300
|
|
+ * DCB entry 2: 02025312 00000010
|
|
+ * DCB entry 3: 02026312 00000020
|
|
+ *
|
|
+ * Identical, except apparently a different connector on a
|
|
+ * different SOR link. Not a clue how we're supposed to know
|
|
+ * which one is in use if it even shares an i2c line...
|
|
+ *
|
|
+ * Ignore the connector on the second SOR link to prevent
|
|
+ * nasty problems until this is sorted (assuming it's not a
|
|
+ * VBIOS bug).
|
|
+ */
|
|
+ if ((dev->pdev->device == 0x040d) &&
|
|
+ (dev->pdev->subsystem_vendor == 0x1028) &&
|
|
+ (dev->pdev->subsystem_device == 0x019b)) {
|
|
+ if (*conn == 0x02026312 && *conf == 0x00000020)
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
static int
|
|
parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
|
|
{
|
|
@@ -5941,6 +5980,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);
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
|
|
index adf4ec2..cc52aec 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
|
|
@@ -81,6 +81,7 @@ struct dcb_connector_table_entry {
|
|
enum dcb_connector_type type;
|
|
uint8_t index2;
|
|
uint8_t gpio_tag;
|
|
+ void *drm;
|
|
};
|
|
|
|
struct dcb_connector_table {
|
|
@@ -117,6 +118,7 @@ struct dcb_entry {
|
|
struct {
|
|
struct sor_conf sor;
|
|
bool use_straps_for_mode;
|
|
+ bool use_acpi_for_edid;
|
|
bool use_power_scripts;
|
|
} lvdsconf;
|
|
struct {
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
|
|
index 6f3c195..d8c341d 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
|
|
@@ -461,9 +461,9 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
|
|
return ret;
|
|
|
|
ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL,
|
|
- evict, no_wait_reserve, no_wait_gpu, new_mem);
|
|
- if (nvbo->channel && nvbo->channel != chan)
|
|
- ret = nouveau_fence_wait(fence, NULL, false, false);
|
|
+ evict || (nvbo->channel &&
|
|
+ nvbo->channel != chan),
|
|
+ no_wait_reserve, no_wait_gpu, new_mem);
|
|
nouveau_fence_unref((void *)&fence);
|
|
return ret;
|
|
}
|
|
@@ -711,8 +711,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
|
|
return ret;
|
|
|
|
/* Software copy if the card isn't up and running yet. */
|
|
- if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE ||
|
|
- !dev_priv->channel) {
|
|
+ if (!dev_priv->channel) {
|
|
ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
|
|
goto out;
|
|
}
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
|
|
index 1fc57ef..e952c3b 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
|
|
@@ -257,9 +257,7 @@ nouveau_channel_free(struct nouveau_channel *chan)
|
|
nouveau_debugfs_channel_fini(chan);
|
|
|
|
/* Give outstanding push buffers a chance to complete */
|
|
- spin_lock_irqsave(&chan->fence.lock, flags);
|
|
nouveau_fence_update(chan);
|
|
- spin_unlock_irqrestore(&chan->fence.lock, flags);
|
|
if (chan->fence.sequence != chan->fence.sequence_ack) {
|
|
struct nouveau_fence *fence = NULL;
|
|
|
|
@@ -368,8 +366,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
|
|
struct nouveau_channel *chan;
|
|
int ret;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
-
|
|
if (dev_priv->engine.graph.accel_blocked)
|
|
return -ENODEV;
|
|
|
|
@@ -418,7 +414,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
|
|
struct drm_nouveau_channel_free *cfree = data;
|
|
struct nouveau_channel *chan;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan);
|
|
|
|
nouveau_channel_free(chan);
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
|
|
index 9a61f3c..2914dd9 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
|
|
@@ -236,20 +236,6 @@ nouveau_connector_detect(struct drm_connector *connector)
|
|
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;
|
|
- }
|
|
-
|
|
/* Cleanup the previous EDID block. */
|
|
if (nv_connector->edid) {
|
|
drm_mode_connector_update_edid_property(connector, NULL);
|
|
@@ -321,6 +307,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)
|
|
{
|
|
@@ -534,21 +599,27 @@ static int
|
|
nouveau_connector_get_modes(struct drm_connector *connector)
|
|
{
|
|
struct drm_device *dev = connector->dev;
|
|
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
|
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
|
|
int ret = 0;
|
|
|
|
- /* If we're not LVDS, destroy the previous native mode, the attached
|
|
- * monitor could have changed.
|
|
+ /* destroy the native mode, the attached monitor could have changed.
|
|
*/
|
|
- if (nv_connector->dcb->type != DCB_CONNECTOR_LVDS &&
|
|
- nv_connector->native_mode) {
|
|
+ if (nv_connector->native_mode) {
|
|
drm_mode_destroy(dev, nv_connector->native_mode);
|
|
nv_connector->native_mode = NULL;
|
|
}
|
|
|
|
if (nv_connector->edid)
|
|
ret = drm_add_edid_modes(connector, nv_connector->edid);
|
|
+ else
|
|
+ if (nv_encoder->dcb->type == OUTPUT_LVDS &&
|
|
+ (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
|
|
+ dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
|
|
+ nv_connector->native_mode = drm_mode_create(dev);
|
|
+ nouveau_bios_fp_mode(dev, nv_connector->native_mode);
|
|
+ }
|
|
|
|
/* Find the native mode if this is a digital panel, if we didn't
|
|
* find any modes through DDC previously add the native mode to
|
|
@@ -569,7 +640,8 @@ nouveau_connector_get_modes(struct drm_connector *connector)
|
|
ret = get_slave_funcs(nv_encoder)->
|
|
get_modes(to_drm_encoder(nv_encoder), connector);
|
|
|
|
- if (nv_encoder->dcb->type == OUTPUT_LVDS)
|
|
+ if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
|
|
+ nv_connector->dcb->type == DCB_CONNECTOR_eDP)
|
|
ret += nouveau_connector_scaler_modes_add(connector);
|
|
|
|
return ret;
|
|
@@ -662,148 +734,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 +809,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,9 +833,6 @@ 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:
|
|
if (dev_priv->card_type >= NV_50) {
|
|
@@ -871,14 +860,12 @@ nouveau_connector_create(struct drm_device *dev,
|
|
}
|
|
|
|
drm_sysfs_connector_add(connector);
|
|
+ dcb->drm = connector;
|
|
+ return dcb->drm;
|
|
|
|
- if (dcb->type == DCB_CONNECTOR_LVDS) {
|
|
- ret = nouveau_connector_create_lvds(dev, connector);
|
|
- if (ret) {
|
|
- connector->funcs->destroy(connector);
|
|
- return ret;
|
|
- }
|
|
- }
|
|
+fail:
|
|
+ drm_connector_cleanup(connector);
|
|
+ kfree(connector);
|
|
+ return ERR_PTR(ret);
|
|
|
|
- return 0;
|
|
}
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
|
|
index 4ef38ab..1ce3d91 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
|
|
@@ -49,7 +49,7 @@ 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);
|
|
|
|
#endif /* __NOUVEAU_CONNECTOR_H__ */
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
|
|
index 65c441a..2e3c6ca 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
|
|
@@ -92,11 +92,9 @@ nouveau_dma_init(struct nouveau_channel *chan)
|
|
return ret;
|
|
|
|
/* Map M2MF notifier object - fbcon. */
|
|
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
|
- ret = nouveau_bo_map(chan->notifier_bo);
|
|
- if (ret)
|
|
- return ret;
|
|
- }
|
|
+ ret = nouveau_bo_map(chan->notifier_bo);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
/* Insert NOPS for NOUVEAU_DMA_SKIPS */
|
|
ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
|
|
index deeb21c..64b4395 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
|
|
@@ -271,12 +273,36 @@ nouveau_dp_link_train(struct drm_encoder *encoder)
|
|
{
|
|
struct drm_device *dev = encoder->dev;
|
|
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
|
- uint8_t config[4];
|
|
- uint8_t status[3];
|
|
+ struct 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.
|
|
+ */
|
|
+ nv50_gpio_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 +429,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 */
|
|
+ nv50_gpio_irq_enable(dev, nv_connector->dcb->gpio_tag, true);
|
|
+
|
|
return eq_done;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
|
|
index 2737704..b4d958c 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
|
|
@@ -35,10 +35,6 @@
|
|
|
|
#include "drm_pciids.h"
|
|
|
|
-MODULE_PARM_DESC(ctxfw, "Use external firmware blob for grctx init (NV40)");
|
|
-int nouveau_ctxfw = 0;
|
|
-module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
|
|
-
|
|
MODULE_PARM_DESC(noagp, "Disable AGP");
|
|
int nouveau_noagp;
|
|
module_param_named(noagp, nouveau_noagp, int, 0400);
|
|
@@ -56,7 +52,7 @@ int nouveau_vram_pushbuf;
|
|
module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
|
|
|
|
MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM");
|
|
-int nouveau_vram_notify = 1;
|
|
+int nouveau_vram_notify = 0;
|
|
module_param_named(vram_notify, nouveau_vram_notify, int, 0400);
|
|
|
|
MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)");
|
|
@@ -155,9 +151,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
|
|
struct drm_crtc *crtc;
|
|
int ret, i;
|
|
|
|
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
- return -ENODEV;
|
|
-
|
|
if (pm_state.event == PM_EVENT_PRETHAW)
|
|
return 0;
|
|
|
|
@@ -257,9 +250,6 @@ nouveau_pci_resume(struct pci_dev *pdev)
|
|
struct drm_crtc *crtc;
|
|
int ret, i;
|
|
|
|
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
- return -ENODEV;
|
|
-
|
|
nouveau_fbcon_save_disable_accel(dev);
|
|
|
|
NV_INFO(dev, "We're back, enabling device...\n");
|
|
@@ -323,7 +313,6 @@ nouveau_pci_resume(struct pci_dev *pdev)
|
|
|
|
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
|
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
|
- int ret;
|
|
|
|
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
|
|
if (!ret)
|
|
@@ -371,7 +360,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 +428,18 @@ static int __init nouveau_init(void)
|
|
nouveau_modeset = 1;
|
|
}
|
|
|
|
- if (nouveau_modeset == 1) {
|
|
- driver.driver_features |= DRIVER_MODESET;
|
|
- nouveau_register_dsm_handler();
|
|
- }
|
|
+ if (!nouveau_modeset)
|
|
+ return 0;
|
|
|
|
+ nouveau_register_dsm_handler();
|
|
return drm_init(&driver);
|
|
}
|
|
|
|
static void __exit nouveau_exit(void)
|
|
{
|
|
+ if (!nouveau_modeset)
|
|
+ return;
|
|
+
|
|
drm_exit(&driver);
|
|
nouveau_unregister_dsm_handler();
|
|
}
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
|
|
index c697191..7584cd7 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
|
|
@@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo)
|
|
return ioptr;
|
|
}
|
|
|
|
-struct mem_block {
|
|
- struct mem_block *next;
|
|
- struct mem_block *prev;
|
|
- uint64_t start;
|
|
- uint64_t size;
|
|
- struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
|
|
-};
|
|
-
|
|
enum nouveau_flags {
|
|
NV_NFORCE = 0x10000000,
|
|
NV_NFORCE2 = 0x20000000
|
|
@@ -149,7 +141,7 @@ struct nouveau_gpuobj {
|
|
struct list_head list;
|
|
|
|
struct nouveau_channel *im_channel;
|
|
- struct mem_block *im_pramin;
|
|
+ struct drm_mm_node *im_pramin;
|
|
struct nouveau_bo *im_backing;
|
|
uint32_t im_backing_start;
|
|
uint32_t *im_backing_suspend;
|
|
@@ -196,7 +188,7 @@ struct nouveau_channel {
|
|
struct list_head pending;
|
|
uint32_t sequence;
|
|
uint32_t sequence_ack;
|
|
- uint32_t last_sequence_irq;
|
|
+ atomic_t last_sequence_irq;
|
|
} fence;
|
|
|
|
/* DMA push buffer */
|
|
@@ -206,7 +198,7 @@ struct nouveau_channel {
|
|
|
|
/* Notifier memory */
|
|
struct nouveau_bo *notifier_bo;
|
|
- struct mem_block *notifier_heap;
|
|
+ struct drm_mm notifier_heap;
|
|
|
|
/* PFIFO context */
|
|
struct nouveau_gpuobj_ref *ramfc;
|
|
@@ -224,7 +216,7 @@ struct nouveau_channel {
|
|
|
|
/* Objects */
|
|
struct nouveau_gpuobj_ref *ramin; /* Private instmem */
|
|
- struct mem_block *ramin_heap; /* Private PRAMIN heap */
|
|
+ struct drm_mm ramin_heap; /* Private PRAMIN heap */
|
|
struct nouveau_gpuobj_ref *ramht; /* Hash table */
|
|
struct list_head ramht_refs; /* Objects referenced by RAMHT */
|
|
|
|
@@ -277,8 +269,7 @@ struct nouveau_instmem_engine {
|
|
void (*clear)(struct drm_device *, struct nouveau_gpuobj *);
|
|
int (*bind)(struct drm_device *, struct nouveau_gpuobj *);
|
|
int (*unbind)(struct drm_device *, struct nouveau_gpuobj *);
|
|
- void (*prepare_access)(struct drm_device *, bool write);
|
|
- void (*finish_access)(struct drm_device *);
|
|
+ void (*flush)(struct drm_device *);
|
|
};
|
|
|
|
struct nouveau_mc_engine {
|
|
@@ -303,10 +294,11 @@ struct nouveau_fb_engine {
|
|
};
|
|
|
|
struct nouveau_fifo_engine {
|
|
- void *priv;
|
|
-
|
|
int channels;
|
|
|
|
+ struct nouveau_gpuobj_ref *playlist[2];
|
|
+ int cur_playlist;
|
|
+
|
|
int (*init)(struct drm_device *);
|
|
void (*takedown)(struct drm_device *);
|
|
|
|
@@ -339,10 +331,11 @@ struct nouveau_pgraph_object_class {
|
|
struct nouveau_pgraph_engine {
|
|
struct nouveau_pgraph_object_class *grclass;
|
|
bool accel_blocked;
|
|
- void *ctxprog;
|
|
- void *ctxvals;
|
|
int grctx_size;
|
|
|
|
+ /* NV2x/NV3x context table (0x400780) */
|
|
+ struct nouveau_gpuobj_ref *ctx_table;
|
|
+
|
|
int (*init)(struct drm_device *);
|
|
void (*takedown)(struct drm_device *);
|
|
|
|
@@ -500,11 +493,6 @@ enum nouveau_card_type {
|
|
|
|
struct drm_nouveau_private {
|
|
struct drm_device *dev;
|
|
- enum {
|
|
- NOUVEAU_CARD_INIT_DOWN,
|
|
- NOUVEAU_CARD_INIT_DONE,
|
|
- NOUVEAU_CARD_INIT_FAILED
|
|
- } init_state;
|
|
|
|
/* the card type, takes NV_* as values */
|
|
enum nouveau_card_type card_type;
|
|
@@ -533,8 +521,6 @@ struct drm_nouveau_private {
|
|
atomic_t validate_sequence;
|
|
} ttm;
|
|
|
|
- struct fb_info *fbdev_info;
|
|
-
|
|
int fifo_alloc_count;
|
|
struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
|
|
|
|
@@ -595,11 +581,7 @@ struct drm_nouveau_private {
|
|
struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
|
|
int vm_vram_pt_nr;
|
|
|
|
- struct mem_block *ramin_heap;
|
|
-
|
|
- /* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */
|
|
- uint32_t ctx_table_size;
|
|
- struct nouveau_gpuobj_ref *ctx_table;
|
|
+ struct drm_mm ramin_heap;
|
|
|
|
struct list_head gpuobj_list;
|
|
|
|
@@ -618,6 +600,11 @@ struct drm_nouveau_private {
|
|
struct backlight_device *backlight;
|
|
|
|
struct nouveau_channel *evo;
|
|
+ struct {
|
|
+ struct dcb_entry *dcb;
|
|
+ u16 script;
|
|
+ u32 pclk;
|
|
+ } evo_irq;
|
|
|
|
struct {
|
|
struct dentry *channel_root;
|
|
@@ -652,14 +639,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
|
|
return 0;
|
|
}
|
|
|
|
-#define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \
|
|
- struct drm_nouveau_private *nv = dev->dev_private; \
|
|
- if (nv->init_state != NOUVEAU_CARD_INIT_DONE) { \
|
|
- NV_ERROR(dev, "called without init\n"); \
|
|
- return -EINVAL; \
|
|
- } \
|
|
-} while (0)
|
|
-
|
|
#define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \
|
|
struct drm_nouveau_private *nv = dev->dev_private; \
|
|
if (!nouveau_channel_owner(dev, (cl), (id))) { \
|
|
@@ -682,7 +661,6 @@ extern int nouveau_tv_disable;
|
|
extern char *nouveau_tv_norm;
|
|
extern int nouveau_reg_debug;
|
|
extern char *nouveau_vbios;
|
|
-extern int nouveau_ctxfw;
|
|
extern int nouveau_ignorelid;
|
|
extern int nouveau_nofbaccel;
|
|
extern int nouveau_noaccel;
|
|
@@ -707,15 +685,7 @@ extern bool nouveau_wait_for_idle(struct drm_device *);
|
|
extern int nouveau_card_init(struct drm_device *);
|
|
|
|
/* nouveau_mem.c */
|
|
-extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start,
|
|
- uint64_t size);
|
|
-extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
|
|
- uint64_t size, int align2,
|
|
- struct drm_file *, int tail);
|
|
-extern void nouveau_mem_takedown(struct mem_block **heap);
|
|
-extern void nouveau_mem_free_block(struct mem_block *);
|
|
extern int nouveau_mem_detect(struct drm_device *dev);
|
|
-extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap);
|
|
extern int nouveau_mem_init(struct drm_device *);
|
|
extern int nouveau_mem_init_agp(struct drm_device *);
|
|
extern void nouveau_mem_close(struct drm_device *);
|
|
@@ -857,11 +827,13 @@ void nouveau_register_dsm_handler(void);
|
|
void nouveau_unregister_dsm_handler(void);
|
|
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
|
|
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
|
|
+int nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
|
|
#else
|
|
static inline void nouveau_register_dsm_handler(void) {}
|
|
static inline void nouveau_unregister_dsm_handler(void) {}
|
|
static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; }
|
|
static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; }
|
|
+static inline int nouveau_acpi_edid(struct drm_device *, struct drm_connector *) { return -EINVAL; }
|
|
#endif
|
|
|
|
/* nouveau_backlight.c */
|
|
@@ -1035,12 +1007,6 @@ extern int nv50_graph_unload_context(struct drm_device *);
|
|
extern void nv50_graph_context_switch(struct drm_device *);
|
|
extern int nv50_grctx_init(struct nouveau_grctx *);
|
|
|
|
-/* nouveau_grctx.c */
|
|
-extern int nouveau_grctx_prog_load(struct drm_device *);
|
|
-extern void nouveau_grctx_vals_load(struct drm_device *,
|
|
- struct nouveau_gpuobj *);
|
|
-extern void nouveau_grctx_fini(struct drm_device *);
|
|
-
|
|
/* nv04_instmem.c */
|
|
extern int nv04_instmem_init(struct drm_device *);
|
|
extern void nv04_instmem_takedown(struct drm_device *);
|
|
@@ -1051,8 +1017,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
|
|
extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
|
|
extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
|
|
extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
|
|
-extern void nv04_instmem_prepare_access(struct drm_device *, bool write);
|
|
-extern void nv04_instmem_finish_access(struct drm_device *);
|
|
+extern void nv04_instmem_flush(struct drm_device *);
|
|
|
|
/* nv50_instmem.c */
|
|
extern int nv50_instmem_init(struct drm_device *);
|
|
@@ -1064,8 +1029,8 @@ 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 nv50_vm_flush(struct drm_device *, int engine);
|
|
|
|
/* nv04_mc.c */
|
|
extern int nv04_mc_init(struct drm_device *);
|
|
@@ -1088,13 +1053,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd,
|
|
unsigned long arg);
|
|
|
|
/* nv04_dac.c */
|
|
-extern int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry);
|
|
+extern int nv04_dac_create(struct drm_connector *, struct dcb_entry *);
|
|
extern uint32_t nv17_dac_sample_load(struct drm_encoder *encoder);
|
|
extern int nv04_dac_output_offset(struct drm_encoder *encoder);
|
|
extern void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable);
|
|
+extern bool nv04_dac_in_use(struct drm_encoder *encoder);
|
|
|
|
/* nv04_dfp.c */
|
|
-extern int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry);
|
|
+extern int nv04_dfp_create(struct drm_connector *, struct dcb_entry *);
|
|
extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent);
|
|
extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent,
|
|
int head, bool dl);
|
|
@@ -1103,10 +1069,10 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode);
|
|
|
|
/* nv04_tv.c */
|
|
extern int nv04_tv_identify(struct drm_device *dev, int i2c_index);
|
|
-extern int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry);
|
|
+extern int nv04_tv_create(struct drm_connector *, struct dcb_entry *);
|
|
|
|
/* nv17_tv.c */
|
|
-extern int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry);
|
|
+extern int nv17_tv_create(struct drm_connector *, struct dcb_entry *);
|
|
|
|
/* nv04_display.c */
|
|
extern int nv04_display_create(struct drm_device *);
|
|
@@ -1147,7 +1113,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 *,
|
|
@@ -1174,6 +1139,7 @@ int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
|
|
/* nv50_gpio.c */
|
|
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 +1186,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;
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
|
|
index e1df820..a1a0d48 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
|
|
@@ -38,13 +38,15 @@ struct nouveau_encoder {
|
|
struct dcb_entry *dcb;
|
|
int or;
|
|
|
|
+ /* different to drm_encoder.crtc, this reflects what's
|
|
+ * actually programmed on the hw, not the proposed crtc */
|
|
+ struct drm_crtc *crtc;
|
|
+
|
|
struct drm_display_mode mode;
|
|
int last_dpms;
|
|
|
|
struct nv04_output_reg restore;
|
|
|
|
- void (*disconnect)(struct nouveau_encoder *encoder);
|
|
-
|
|
union {
|
|
struct {
|
|
int mc_unknown;
|
|
@@ -71,8 +73,8 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
|
|
|
|
struct nouveau_connector *
|
|
nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
|
|
-int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry);
|
|
-int nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry);
|
|
+int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
|
|
+int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
|
|
|
|
struct bit_displayport_encoder_table {
|
|
uint32_t match;
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
|
|
index 0a59f96..8415049 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
|
|
@@ -337,7 +337,7 @@ static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper)
|
|
drm_helper_fb_hotplug_event(fb_helper, true);
|
|
}
|
|
|
|
-int
|
|
+static int
|
|
nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
|
|
{
|
|
struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb;
|
|
@@ -392,7 +392,8 @@ int nouveau_fbcon_init(struct drm_device *dev)
|
|
dev_priv->nfbdev = nfbdev;
|
|
nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
|
|
|
|
- ret = drm_fb_helper_init(dev, &nfbdev->helper, 2, 4, true);
|
|
+ ret = drm_fb_helper_init(dev, &nfbdev->helper,
|
|
+ nv_two_heads(dev) ? 2 : 1, 4, true);
|
|
if (ret) {
|
|
kfree(nfbdev);
|
|
return ret;
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
|
|
index faddf53..813d853 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
|
|
@@ -67,12 +67,13 @@ nouveau_fence_update(struct nouveau_channel *chan)
|
|
if (USE_REFCNT)
|
|
sequence = nvchan_rd32(chan, 0x48);
|
|
else
|
|
- sequence = chan->fence.last_sequence_irq;
|
|
+ sequence = atomic_read(&chan->fence.last_sequence_irq);
|
|
|
|
if (chan->fence.sequence_ack == sequence)
|
|
return;
|
|
chan->fence.sequence_ack = sequence;
|
|
|
|
+ spin_lock(&chan->fence.lock);
|
|
list_for_each_safe(entry, tmp, &chan->fence.pending) {
|
|
fence = list_entry(entry, struct nouveau_fence, entry);
|
|
|
|
@@ -84,6 +85,7 @@ nouveau_fence_update(struct nouveau_channel *chan)
|
|
if (sequence == chan->fence.sequence_ack)
|
|
break;
|
|
}
|
|
+ spin_unlock(&chan->fence.lock);
|
|
}
|
|
|
|
int
|
|
@@ -119,7 +121,6 @@ nouveau_fence_emit(struct nouveau_fence *fence)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = fence->channel->dev->dev_private;
|
|
struct nouveau_channel *chan = fence->channel;
|
|
- unsigned long flags;
|
|
int ret;
|
|
|
|
ret = RING_SPACE(chan, 2);
|
|
@@ -127,9 +128,7 @@ nouveau_fence_emit(struct nouveau_fence *fence)
|
|
return ret;
|
|
|
|
if (unlikely(chan->fence.sequence == chan->fence.sequence_ack - 1)) {
|
|
- spin_lock_irqsave(&chan->fence.lock, flags);
|
|
nouveau_fence_update(chan);
|
|
- spin_unlock_irqrestore(&chan->fence.lock, flags);
|
|
|
|
BUG_ON(chan->fence.sequence ==
|
|
chan->fence.sequence_ack - 1);
|
|
@@ -138,9 +137,9 @@ nouveau_fence_emit(struct nouveau_fence *fence)
|
|
fence->sequence = ++chan->fence.sequence;
|
|
|
|
kref_get(&fence->refcount);
|
|
- spin_lock_irqsave(&chan->fence.lock, flags);
|
|
+ spin_lock(&chan->fence.lock);
|
|
list_add_tail(&fence->entry, &chan->fence.pending);
|
|
- spin_unlock_irqrestore(&chan->fence.lock, flags);
|
|
+ spin_unlock(&chan->fence.lock);
|
|
|
|
BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1);
|
|
OUT_RING(chan, fence->sequence);
|
|
@@ -173,14 +172,11 @@ nouveau_fence_signalled(void *sync_obj, void *sync_arg)
|
|
{
|
|
struct nouveau_fence *fence = nouveau_fence(sync_obj);
|
|
struct nouveau_channel *chan = fence->channel;
|
|
- unsigned long flags;
|
|
|
|
if (fence->signalled)
|
|
return true;
|
|
|
|
- spin_lock_irqsave(&chan->fence.lock, flags);
|
|
nouveau_fence_update(chan);
|
|
- spin_unlock_irqrestore(&chan->fence.lock, flags);
|
|
return fence->signalled;
|
|
}
|
|
|
|
@@ -221,27 +217,12 @@ nouveau_fence_flush(void *sync_obj, void *sync_arg)
|
|
return 0;
|
|
}
|
|
|
|
-void
|
|
-nouveau_fence_handler(struct drm_device *dev, int channel)
|
|
-{
|
|
- struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- struct nouveau_channel *chan = NULL;
|
|
-
|
|
- if (channel >= 0 && channel < dev_priv->engine.fifo.channels)
|
|
- chan = dev_priv->fifos[channel];
|
|
-
|
|
- if (chan) {
|
|
- spin_lock_irq(&chan->fence.lock);
|
|
- nouveau_fence_update(chan);
|
|
- spin_unlock_irq(&chan->fence.lock);
|
|
- }
|
|
-}
|
|
-
|
|
int
|
|
nouveau_fence_init(struct nouveau_channel *chan)
|
|
{
|
|
INIT_LIST_HEAD(&chan->fence.pending);
|
|
spin_lock_init(&chan->fence.lock);
|
|
+ atomic_set(&chan->fence.last_sequence_irq, 0);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
|
|
index 69c76cf..547f2c2 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
|
|
@@ -137,8 +137,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
|
|
uint32_t flags = 0;
|
|
int ret = 0;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
-
|
|
if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL))
|
|
dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping;
|
|
|
|
@@ -577,10 +575,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
|
|
struct drm_nouveau_gem_pushbuf_bo *bo;
|
|
struct nouveau_channel *chan;
|
|
struct validate_op op;
|
|
- struct nouveau_fence *fence = 0;
|
|
+ struct nouveau_fence *fence = NULL;
|
|
int i, j, ret = 0, do_reloc = 0;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan);
|
|
|
|
req->vram_available = dev_priv->fb_aper_free;
|
|
@@ -760,8 +757,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
|
|
bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT);
|
|
int ret = -EINVAL;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
-
|
|
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
|
|
if (!gem)
|
|
return ret;
|
|
@@ -800,8 +795,6 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
|
|
struct nouveau_bo *nvbo;
|
|
int ret = -EINVAL;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
-
|
|
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
|
|
if (!gem)
|
|
return ret;
|
|
@@ -827,8 +820,6 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data,
|
|
struct drm_gem_object *gem;
|
|
int ret;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
-
|
|
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
|
|
if (!gem)
|
|
return -EINVAL;
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c
|
|
deleted file mode 100644
|
|
index f731c5f..0000000
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_grctx.c
|
|
+++ /dev/null
|
|
@@ -1,160 +0,0 @@
|
|
-/*
|
|
- * Copyright 2009 Red Hat Inc.
|
|
- *
|
|
- * Permission is hereby granted, free of charge, to any person obtaining a
|
|
- * copy of this software and associated documentation files (the "Software"),
|
|
- * to deal in the Software without restriction, including without limitation
|
|
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
- * and/or sell copies of the Software, and to permit persons to whom the
|
|
- * Software is furnished to do so, subject to the following conditions:
|
|
- *
|
|
- * The above copyright notice and this permission notice shall be included in
|
|
- * all copies or substantial portions of the Software.
|
|
- *
|
|
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
- * OTHER DEALINGS IN THE SOFTWARE.
|
|
- *
|
|
- * Authors: Ben Skeggs
|
|
- */
|
|
-
|
|
-#include <linux/firmware.h>
|
|
-#include <linux/slab.h>
|
|
-
|
|
-#include "drmP.h"
|
|
-#include "nouveau_drv.h"
|
|
-
|
|
-struct nouveau_ctxprog {
|
|
- uint32_t signature;
|
|
- uint8_t version;
|
|
- uint16_t length;
|
|
- uint32_t data[];
|
|
-} __attribute__ ((packed));
|
|
-
|
|
-struct nouveau_ctxvals {
|
|
- uint32_t signature;
|
|
- uint8_t version;
|
|
- uint32_t length;
|
|
- struct {
|
|
- uint32_t offset;
|
|
- uint32_t value;
|
|
- } data[];
|
|
-} __attribute__ ((packed));
|
|
-
|
|
-int
|
|
-nouveau_grctx_prog_load(struct drm_device *dev)
|
|
-{
|
|
- struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
- const int chipset = dev_priv->chipset;
|
|
- const struct firmware *fw;
|
|
- const struct nouveau_ctxprog *cp;
|
|
- const struct nouveau_ctxvals *cv;
|
|
- char name[32];
|
|
- int ret, i;
|
|
-
|
|
- if (pgraph->accel_blocked)
|
|
- return -ENODEV;
|
|
-
|
|
- if (!pgraph->ctxprog) {
|
|
- sprintf(name, "nouveau/nv%02x.ctxprog", chipset);
|
|
- ret = request_firmware(&fw, name, &dev->pdev->dev);
|
|
- if (ret) {
|
|
- NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset);
|
|
- return ret;
|
|
- }
|
|
-
|
|
- pgraph->ctxprog = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
|
- if (!pgraph->ctxprog) {
|
|
- NV_ERROR(dev, "OOM copying ctxprog\n");
|
|
- release_firmware(fw);
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
- cp = pgraph->ctxprog;
|
|
- if (le32_to_cpu(cp->signature) != 0x5043564e ||
|
|
- cp->version != 0 ||
|
|
- le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
|
|
- NV_ERROR(dev, "ctxprog invalid\n");
|
|
- release_firmware(fw);
|
|
- nouveau_grctx_fini(dev);
|
|
- return -EINVAL;
|
|
- }
|
|
- release_firmware(fw);
|
|
- }
|
|
-
|
|
- if (!pgraph->ctxvals) {
|
|
- sprintf(name, "nouveau/nv%02x.ctxvals", chipset);
|
|
- ret = request_firmware(&fw, name, &dev->pdev->dev);
|
|
- if (ret) {
|
|
- NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset);
|
|
- nouveau_grctx_fini(dev);
|
|
- return ret;
|
|
- }
|
|
-
|
|
- pgraph->ctxvals = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
|
- if (!pgraph->ctxvals) {
|
|
- NV_ERROR(dev, "OOM copying ctxvals\n");
|
|
- release_firmware(fw);
|
|
- nouveau_grctx_fini(dev);
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
- cv = (void *)pgraph->ctxvals;
|
|
- if (le32_to_cpu(cv->signature) != 0x5643564e ||
|
|
- cv->version != 0 ||
|
|
- le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
|
|
- NV_ERROR(dev, "ctxvals invalid\n");
|
|
- release_firmware(fw);
|
|
- nouveau_grctx_fini(dev);
|
|
- return -EINVAL;
|
|
- }
|
|
- release_firmware(fw);
|
|
- }
|
|
-
|
|
- cp = pgraph->ctxprog;
|
|
-
|
|
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
|
|
- for (i = 0; i < le16_to_cpu(cp->length); i++)
|
|
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
|
|
- le32_to_cpu(cp->data[i]));
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-void
|
|
-nouveau_grctx_fini(struct drm_device *dev)
|
|
-{
|
|
- struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
-
|
|
- if (pgraph->ctxprog) {
|
|
- kfree(pgraph->ctxprog);
|
|
- pgraph->ctxprog = NULL;
|
|
- }
|
|
-
|
|
- if (pgraph->ctxvals) {
|
|
- kfree(pgraph->ctxprog);
|
|
- pgraph->ctxvals = NULL;
|
|
- }
|
|
-}
|
|
-
|
|
-void
|
|
-nouveau_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
|
|
-{
|
|
- struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
- struct nouveau_ctxvals *cv = pgraph->ctxvals;
|
|
- int i;
|
|
-
|
|
- if (!cv)
|
|
- return;
|
|
-
|
|
- for (i = 0; i < le32_to_cpu(cv->length); i++)
|
|
- nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
|
|
- le32_to_cpu(cv->data[i].value));
|
|
-}
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
|
|
index c1fd42b..09db6f6 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);
|
|
+ dev_priv->engine.instmem.flush(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;
|
|
- }
|
|
-
|
|
- nv_wr32(dev, 0x100c80, 0x00060001);
|
|
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
|
|
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
|
|
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
|
|
- }
|
|
+ nv50_vm_flush(dev, 5);
|
|
+ nv50_vm_flush(dev, 0);
|
|
+ nv50_vm_flush(dev, 4);
|
|
+ nv50_vm_flush(dev, 6);
|
|
}
|
|
|
|
/*
|
|
* Cleanup everything
|
|
*/
|
|
-void nouveau_mem_takedown(struct mem_block **heap)
|
|
-{
|
|
- struct mem_block *p;
|
|
-
|
|
- if (!*heap)
|
|
- return;
|
|
-
|
|
- for (p = (*heap)->next; p != *heap;) {
|
|
- struct mem_block *q = p;
|
|
- p = p->next;
|
|
- kfree(q);
|
|
- }
|
|
-
|
|
- kfree(*heap);
|
|
- *heap = NULL;
|
|
-}
|
|
-
|
|
-void nouveau_mem_close(struct drm_device *dev)
|
|
+void
|
|
+nouveau_mem_close(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
|
|
@@ -449,8 +229,7 @@ void nouveau_mem_close(struct drm_device *dev)
|
|
|
|
nouveau_ttm_global_release(dev_priv);
|
|
|
|
- if (drm_core_has_AGP(dev) && dev->agp &&
|
|
- drm_core_check_feature(dev, DRIVER_MODESET)) {
|
|
+ if (drm_core_has_AGP(dev) && dev->agp) {
|
|
struct drm_agp_mem *entry, *tempe;
|
|
|
|
/* Remove AGP resources, but leave dev->agp
|
|
@@ -470,10 +249,10 @@ void nouveau_mem_close(struct drm_device *dev)
|
|
dev->agp->enabled = 0;
|
|
}
|
|
|
|
- if (dev_priv->fb_mtrr) {
|
|
+ if (dev_priv->fb_mtrr >= 0) {
|
|
drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1),
|
|
drm_get_resource_len(dev, 1), DRM_MTRR_WC);
|
|
- dev_priv->fb_mtrr = 0;
|
|
+ dev_priv->fb_mtrr = -1;
|
|
}
|
|
}
|
|
|
|
@@ -536,12 +315,18 @@ nouveau_mem_detect(struct drm_device *dev)
|
|
} else
|
|
if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
|
|
dev_priv->vram_size = nouveau_mem_detect_nforce(dev);
|
|
- } else {
|
|
+ } else
|
|
+ if (dev_priv->card_type < NV_50) {
|
|
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 {
|
|
+ dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA);
|
|
+ dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
|
|
+ dev_priv->vram_size &= 0xffffffff00ll;
|
|
+ if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) {
|
|
dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
|
|
dev_priv->vram_sys_base <<= 12;
|
|
+ }
|
|
}
|
|
|
|
NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
|
|
index 9537f3e..3ec181f 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c
|
|
@@ -55,7 +55,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
|
|
if (ret)
|
|
goto out_err;
|
|
|
|
- ret = nouveau_mem_init_heap(&chan->notifier_heap, 0, ntfy->bo.mem.size);
|
|
+ ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);
|
|
if (ret)
|
|
goto out_err;
|
|
|
|
@@ -80,7 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
|
|
nouveau_bo_unpin(chan->notifier_bo);
|
|
mutex_unlock(&dev->struct_mutex);
|
|
drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
|
|
- nouveau_mem_takedown(&chan->notifier_heap);
|
|
+ drm_mm_takedown(&chan->notifier_heap);
|
|
}
|
|
|
|
static void
|
|
@@ -90,7 +90,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
|
|
NV_DEBUG(dev, "\n");
|
|
|
|
if (gpuobj->priv)
|
|
- nouveau_mem_free_block(gpuobj->priv);
|
|
+ drm_mm_put_block(gpuobj->priv);
|
|
}
|
|
|
|
int
|
|
@@ -100,18 +100,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
|
|
struct drm_device *dev = chan->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_gpuobj *nobj = NULL;
|
|
- struct mem_block *mem;
|
|
+ struct drm_mm_node *mem;
|
|
uint32_t offset;
|
|
int target, ret;
|
|
|
|
- if (!chan->notifier_heap) {
|
|
- NV_ERROR(dev, "Channel %d doesn't have a notifier heap!\n",
|
|
- chan->id);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- mem = nouveau_mem_alloc_block(chan->notifier_heap, size, 0,
|
|
- (struct drm_file *)-2, 0);
|
|
+ mem = drm_mm_search_free(&chan->notifier_heap, size, 0, 0);
|
|
+ if (mem)
|
|
+ mem = drm_mm_get_block(mem, size, 0);
|
|
if (!mem) {
|
|
NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
|
|
return -ENOMEM;
|
|
@@ -144,17 +139,17 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
|
|
mem->size, NV_DMA_ACCESS_RW, target,
|
|
&nobj);
|
|
if (ret) {
|
|
- nouveau_mem_free_block(mem);
|
|
+ drm_mm_put_block(mem);
|
|
NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret);
|
|
return ret;
|
|
}
|
|
- nobj->dtor = nouveau_notifier_gpuobj_dtor;
|
|
- nobj->priv = mem;
|
|
+ nobj->dtor = nouveau_notifier_gpuobj_dtor;
|
|
+ nobj->priv = mem;
|
|
|
|
ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
|
|
if (ret) {
|
|
nouveau_gpuobj_del(dev, &nobj);
|
|
- nouveau_mem_free_block(mem);
|
|
+ drm_mm_put_block(mem);
|
|
NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
|
|
return ret;
|
|
}
|
|
@@ -170,7 +165,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)
|
|
return -EINVAL;
|
|
|
|
if (poffset) {
|
|
- struct mem_block *mem = nobj->priv;
|
|
+ struct drm_mm_node *mem = nobj->priv;
|
|
|
|
if (*poffset >= mem->size)
|
|
return false;
|
|
@@ -189,7 +184,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
|
|
struct nouveau_channel *chan;
|
|
int ret;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan);
|
|
|
|
ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset);
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
|
|
index e7c100b..4bf6b33 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
|
|
@@ -132,7 +132,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
|
|
}
|
|
}
|
|
|
|
- instmem->prepare_access(dev, true);
|
|
co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
|
|
do {
|
|
if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
|
|
@@ -143,7 +142,7 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
|
|
nv_wo32(dev, ramht, (co + 4)/4, ctx);
|
|
|
|
list_add_tail(&ref->list, &chan->ramht_refs);
|
|
- instmem->finish_access(dev);
|
|
+ instmem->flush(dev);
|
|
return 0;
|
|
}
|
|
NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
|
|
@@ -153,7 +152,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
|
|
if (co >= dev_priv->ramht_size)
|
|
co = 0;
|
|
} while (co != ho);
|
|
- instmem->finish_access(dev);
|
|
|
|
NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
|
|
return -ENOMEM;
|
|
@@ -173,7 +171,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
|
|
return;
|
|
}
|
|
|
|
- instmem->prepare_access(dev, true);
|
|
co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
|
|
do {
|
|
if (nouveau_ramht_entry_valid(dev, ramht, co) &&
|
|
@@ -186,7 +183,7 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
|
|
nv_wo32(dev, ramht, (co + 4)/4, 0x00000000);
|
|
|
|
list_del(&ref->list);
|
|
- instmem->finish_access(dev);
|
|
+ instmem->flush(dev);
|
|
return;
|
|
}
|
|
|
|
@@ -195,7 +192,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
|
|
co = 0;
|
|
} while (co != ho);
|
|
list_del(&ref->list);
|
|
- instmem->finish_access(dev);
|
|
|
|
NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
|
|
chan->id, ref->handle);
|
|
@@ -209,7 +205,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_engine *engine = &dev_priv->engine;
|
|
struct nouveau_gpuobj *gpuobj;
|
|
- struct mem_block *pramin = NULL;
|
|
+ struct drm_mm *pramin = NULL;
|
|
int ret;
|
|
|
|
NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
|
|
@@ -233,25 +229,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
|
|
* available.
|
|
*/
|
|
if (chan) {
|
|
- if (chan->ramin_heap) {
|
|
- NV_DEBUG(dev, "private heap\n");
|
|
- pramin = chan->ramin_heap;
|
|
- } else
|
|
- if (dev_priv->card_type < NV_50) {
|
|
- NV_DEBUG(dev, "global heap fallback\n");
|
|
- pramin = dev_priv->ramin_heap;
|
|
- }
|
|
+ NV_DEBUG(dev, "channel heap\n");
|
|
+ pramin = &chan->ramin_heap;
|
|
} else {
|
|
NV_DEBUG(dev, "global heap\n");
|
|
- pramin = dev_priv->ramin_heap;
|
|
- }
|
|
-
|
|
- if (!pramin) {
|
|
- NV_ERROR(dev, "No PRAMIN heap!\n");
|
|
- return -EINVAL;
|
|
- }
|
|
+ pramin = &dev_priv->ramin_heap;
|
|
|
|
- if (!chan) {
|
|
ret = engine->instmem.populate(dev, gpuobj, &size);
|
|
if (ret) {
|
|
nouveau_gpuobj_del(dev, &gpuobj);
|
|
@@ -260,9 +243,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
|
|
}
|
|
|
|
/* Allocate a chunk of the PRAMIN aperture */
|
|
- gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size,
|
|
- drm_order(align),
|
|
- (struct drm_file *)-2, 0);
|
|
+ gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
|
|
+ if (gpuobj->im_pramin)
|
|
+ gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
|
|
+
|
|
if (!gpuobj->im_pramin) {
|
|
nouveau_gpuobj_del(dev, &gpuobj);
|
|
return -ENOMEM;
|
|
@@ -279,10 +263,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
|
|
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
|
|
int i;
|
|
|
|
- engine->instmem.prepare_access(dev, true);
|
|
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
|
|
nv_wo32(dev, gpuobj, i/4, 0);
|
|
- engine->instmem.finish_access(dev);
|
|
+ engine->instmem.flush(dev);
|
|
}
|
|
|
|
*gpuobj_ret = gpuobj;
|
|
@@ -370,10 +353,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
|
|
}
|
|
|
|
if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
|
|
- engine->instmem.prepare_access(dev, true);
|
|
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
|
|
nv_wo32(dev, gpuobj, i/4, 0);
|
|
- engine->instmem.finish_access(dev);
|
|
+ engine->instmem.flush(dev);
|
|
}
|
|
|
|
if (gpuobj->dtor)
|
|
@@ -386,7 +368,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
|
|
if (gpuobj->flags & NVOBJ_FLAG_FAKE)
|
|
kfree(gpuobj->im_pramin);
|
|
else
|
|
- nouveau_mem_free_block(gpuobj->im_pramin);
|
|
+ drm_mm_put_block(gpuobj->im_pramin);
|
|
}
|
|
|
|
list_del(&gpuobj->list);
|
|
@@ -589,7 +571,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
|
|
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
|
|
|
|
if (p_offset != ~0) {
|
|
- gpuobj->im_pramin = kzalloc(sizeof(struct mem_block),
|
|
+ gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
|
|
GFP_KERNEL);
|
|
if (!gpuobj->im_pramin) {
|
|
nouveau_gpuobj_del(dev, &gpuobj);
|
|
@@ -605,10 +587,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
|
|
}
|
|
|
|
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
|
|
nv_wo32(dev, gpuobj, i/4, 0);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
}
|
|
|
|
if (pref) {
|
|
@@ -696,8 +677,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
|
|
return ret;
|
|
}
|
|
|
|
- instmem->prepare_access(dev, true);
|
|
-
|
|
if (dev_priv->card_type < NV_50) {
|
|
uint32_t frame, adjust, pte_flags = 0;
|
|
|
|
@@ -734,7 +713,7 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
|
|
nv_wo32(dev, *gpuobj, 5, flags5);
|
|
}
|
|
|
|
- instmem->finish_access(dev);
|
|
+ instmem->flush(dev);
|
|
|
|
(*gpuobj)->engine = NVOBJ_ENGINE_SW;
|
|
(*gpuobj)->class = class;
|
|
@@ -849,7 +828,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
|
|
return ret;
|
|
}
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
if (dev_priv->card_type >= NV_50) {
|
|
nv_wo32(dev, *gpuobj, 0, class);
|
|
nv_wo32(dev, *gpuobj, 5, 0x00010000);
|
|
@@ -874,7 +852,7 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
|
|
}
|
|
}
|
|
}
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
|
|
(*gpuobj)->engine = NVOBJ_ENGINE_GR;
|
|
(*gpuobj)->class = class;
|
|
@@ -920,6 +898,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
|
|
base = 0;
|
|
|
|
/* PGRAPH context */
|
|
+ size += dev_priv->engine.graph.grctx_size;
|
|
|
|
if (dev_priv->card_type == NV_50) {
|
|
/* Various fixed table thingos */
|
|
@@ -930,12 +909,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
|
|
size += 0x8000;
|
|
/* RAMFC */
|
|
size += 0x1000;
|
|
- /* PGRAPH context */
|
|
- size += 0x70000;
|
|
}
|
|
|
|
- NV_DEBUG(dev, "ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n",
|
|
- chan->id, size, base);
|
|
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
|
|
&chan->ramin);
|
|
if (ret) {
|
|
@@ -944,8 +919,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
|
|
}
|
|
pramin = chan->ramin->gpuobj;
|
|
|
|
- ret = nouveau_mem_init_heap(&chan->ramin_heap,
|
|
- pramin->im_pramin->start + base, size);
|
|
+ ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
|
|
if (ret) {
|
|
NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
|
|
nouveau_gpuobj_ref_del(dev, &chan->ramin);
|
|
@@ -969,15 +943,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
|
|
|
|
NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
|
|
|
|
- /* Reserve a block of PRAMIN for the channel
|
|
- *XXX: maybe on <NV50 too at some point
|
|
- */
|
|
- if (0 || dev_priv->card_type == NV_50) {
|
|
- ret = nouveau_gpuobj_channel_init_pramin(chan);
|
|
- if (ret) {
|
|
- NV_ERROR(dev, "init pramin\n");
|
|
- return ret;
|
|
- }
|
|
+ /* Allocate a chunk of memory for per-channel object storage */
|
|
+ ret = nouveau_gpuobj_channel_init_pramin(chan);
|
|
+ if (ret) {
|
|
+ NV_ERROR(dev, "init pramin\n");
|
|
+ return ret;
|
|
}
|
|
|
|
/* NV50 VM
|
|
@@ -988,17 +958,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
|
|
if (dev_priv->card_type >= NV_50) {
|
|
uint32_t vm_offset, pde;
|
|
|
|
- instmem->prepare_access(dev, true);
|
|
-
|
|
vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
|
|
vm_offset += chan->ramin->gpuobj->im_pramin->start;
|
|
|
|
ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
|
|
0, &chan->vm_pd, NULL);
|
|
- if (ret) {
|
|
- instmem->finish_access(dev);
|
|
+ if (ret)
|
|
return ret;
|
|
- }
|
|
for (i = 0; i < 0x4000; i += 8) {
|
|
nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000);
|
|
nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe);
|
|
@@ -1008,10 +974,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
|
|
ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
|
|
dev_priv->gart_info.sg_ctxdma,
|
|
&chan->vm_gart_pt);
|
|
- if (ret) {
|
|
- instmem->finish_access(dev);
|
|
+ if (ret)
|
|
return ret;
|
|
- }
|
|
nv_wo32(dev, chan->vm_pd, pde++,
|
|
chan->vm_gart_pt->instance | 0x03);
|
|
nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
|
|
@@ -1021,17 +985,15 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
|
|
ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
|
|
dev_priv->vm_vram_pt[i],
|
|
&chan->vm_vram_pt[i]);
|
|
- if (ret) {
|
|
- instmem->finish_access(dev);
|
|
+ if (ret)
|
|
return ret;
|
|
- }
|
|
|
|
nv_wo32(dev, chan->vm_pd, pde++,
|
|
chan->vm_vram_pt[i]->instance | 0x61);
|
|
nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
|
|
}
|
|
|
|
- instmem->finish_access(dev);
|
|
+ instmem->flush(dev);
|
|
}
|
|
|
|
/* RAMHT */
|
|
@@ -1130,8 +1092,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
|
|
for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
|
|
nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
|
|
|
|
- if (chan->ramin_heap)
|
|
- nouveau_mem_takedown(&chan->ramin_heap);
|
|
+ if (chan->ramin_heap.fl_entry.next)
|
|
+ drm_mm_takedown(&chan->ramin_heap);
|
|
if (chan->ramin)
|
|
nouveau_gpuobj_ref_del(dev, &chan->ramin);
|
|
|
|
@@ -1164,10 +1126,8 @@ nouveau_gpuobj_suspend(struct drm_device *dev)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, false);
|
|
for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
|
|
gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
}
|
|
|
|
return 0;
|
|
@@ -1212,10 +1172,9 @@ nouveau_gpuobj_resume(struct drm_device *dev)
|
|
if (!gpuobj->im_backing_suspend)
|
|
continue;
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
|
|
nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
}
|
|
|
|
nouveau_gpuobj_suspend_cleanup(dev);
|
|
@@ -1232,7 +1191,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
|
|
struct nouveau_channel *chan;
|
|
int ret;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan);
|
|
|
|
if (init->handle == ~0)
|
|
@@ -1283,7 +1241,6 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
|
|
struct nouveau_channel *chan;
|
|
int ret;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
|
|
|
|
ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref);
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
|
|
index 6ca80a3..b6391a1 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
|
|
@@ -814,6 +814,7 @@
|
|
#define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000
|
|
#define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff
|
|
#define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80)
|
|
+#define NV50_SOR_DP_CTRL_ENABLED 0x00000001
|
|
#define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000
|
|
#define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000
|
|
#define NV50_SOR_DP_CTRL_LANE_0_ENABLED 0x00010000
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
|
|
index 1d6ee8b..491767f 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
|
|
@@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
|
|
|
|
NV_DEBUG(dev, "pg=0x%lx\n", mem->mm_node->start);
|
|
|
|
- dev_priv->engine.instmem.prepare_access(nvbe->dev, true);
|
|
pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT);
|
|
nvbe->pte_start = pte;
|
|
for (i = 0; i < nvbe->nr_pages; i++) {
|
|
@@ -116,24 +115,11 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
|
|
dma_offset += NV_CTXDMA_PAGE_SIZE;
|
|
}
|
|
}
|
|
- dev_priv->engine.instmem.finish_access(nvbe->dev);
|
|
+ dev_priv->engine.instmem.flush(nvbe->dev);
|
|
|
|
if (dev_priv->card_type == NV_50) {
|
|
- nv_wr32(dev, 0x100c80, 0x00050001);
|
|
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
|
|
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
|
|
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
|
|
- nv_rd32(dev, 0x100c80));
|
|
- return -EBUSY;
|
|
- }
|
|
-
|
|
- nv_wr32(dev, 0x100c80, 0x00000001);
|
|
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
|
|
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
|
|
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
|
|
- nv_rd32(dev, 0x100c80));
|
|
- return -EBUSY;
|
|
- }
|
|
+ nv50_vm_flush(dev, 5); /* PGRAPH */
|
|
+ nv50_vm_flush(dev, 0); /* PFIFO */
|
|
}
|
|
|
|
nvbe->bound = true;
|
|
@@ -154,7 +140,6 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
|
|
if (!nvbe->bound)
|
|
return 0;
|
|
|
|
- dev_priv->engine.instmem.prepare_access(nvbe->dev, true);
|
|
pte = nvbe->pte_start;
|
|
for (i = 0; i < nvbe->nr_pages; i++) {
|
|
dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus;
|
|
@@ -170,24 +155,11 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
|
|
dma_offset += NV_CTXDMA_PAGE_SIZE;
|
|
}
|
|
}
|
|
- dev_priv->engine.instmem.finish_access(nvbe->dev);
|
|
+ dev_priv->engine.instmem.flush(nvbe->dev);
|
|
|
|
if (dev_priv->card_type == NV_50) {
|
|
- nv_wr32(dev, 0x100c80, 0x00050001);
|
|
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
|
|
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
|
|
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
|
|
- nv_rd32(dev, 0x100c80));
|
|
- return -EBUSY;
|
|
- }
|
|
-
|
|
- nv_wr32(dev, 0x100c80, 0x00000001);
|
|
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
|
|
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
|
|
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
|
|
- nv_rd32(dev, 0x100c80));
|
|
- return -EBUSY;
|
|
- }
|
|
+ nv50_vm_flush(dev, 5);
|
|
+ nv50_vm_flush(dev, 0);
|
|
}
|
|
|
|
nvbe->bound = false;
|
|
@@ -272,7 +244,6 @@ nouveau_sgdma_init(struct drm_device *dev)
|
|
pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0,
|
|
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
if (dev_priv->card_type < NV_50) {
|
|
/* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and
|
|
* confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE
|
|
@@ -294,7 +265,7 @@ nouveau_sgdma_init(struct drm_device *dev)
|
|
nv_wo32(dev, gpuobj, (i+4)/4, 0);
|
|
}
|
|
}
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
|
|
dev_priv->gart_info.type = NOUVEAU_GART_SGDMA;
|
|
dev_priv->gart_info.aper_base = 0;
|
|
@@ -325,14 +296,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
|
|
- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
|
|
int pte;
|
|
|
|
pte = (offset >> NV_CTXDMA_PAGE_SHIFT);
|
|
if (dev_priv->card_type < NV_50) {
|
|
- instmem->prepare_access(dev, false);
|
|
*page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK;
|
|
- instmem->finish_access(dev);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
|
|
index 4c26be6..63c2d24 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
|
|
@@ -54,8 +54,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
|
engine->instmem.clear = nv04_instmem_clear;
|
|
engine->instmem.bind = nv04_instmem_bind;
|
|
engine->instmem.unbind = nv04_instmem_unbind;
|
|
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
|
|
- engine->instmem.finish_access = nv04_instmem_finish_access;
|
|
+ engine->instmem.flush = nv04_instmem_flush;
|
|
engine->mc.init = nv04_mc_init;
|
|
engine->mc.takedown = nv04_mc_takedown;
|
|
engine->timer.init = nv04_timer_init;
|
|
@@ -95,8 +94,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
|
engine->instmem.clear = nv04_instmem_clear;
|
|
engine->instmem.bind = nv04_instmem_bind;
|
|
engine->instmem.unbind = nv04_instmem_unbind;
|
|
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
|
|
- engine->instmem.finish_access = nv04_instmem_finish_access;
|
|
+ engine->instmem.flush = nv04_instmem_flush;
|
|
engine->mc.init = nv04_mc_init;
|
|
engine->mc.takedown = nv04_mc_takedown;
|
|
engine->timer.init = nv04_timer_init;
|
|
@@ -138,8 +136,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
|
engine->instmem.clear = nv04_instmem_clear;
|
|
engine->instmem.bind = nv04_instmem_bind;
|
|
engine->instmem.unbind = nv04_instmem_unbind;
|
|
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
|
|
- engine->instmem.finish_access = nv04_instmem_finish_access;
|
|
+ engine->instmem.flush = nv04_instmem_flush;
|
|
engine->mc.init = nv04_mc_init;
|
|
engine->mc.takedown = nv04_mc_takedown;
|
|
engine->timer.init = nv04_timer_init;
|
|
@@ -181,8 +178,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
|
engine->instmem.clear = nv04_instmem_clear;
|
|
engine->instmem.bind = nv04_instmem_bind;
|
|
engine->instmem.unbind = nv04_instmem_unbind;
|
|
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
|
|
- engine->instmem.finish_access = nv04_instmem_finish_access;
|
|
+ engine->instmem.flush = nv04_instmem_flush;
|
|
engine->mc.init = nv04_mc_init;
|
|
engine->mc.takedown = nv04_mc_takedown;
|
|
engine->timer.init = nv04_timer_init;
|
|
@@ -225,8 +221,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
|
engine->instmem.clear = nv04_instmem_clear;
|
|
engine->instmem.bind = nv04_instmem_bind;
|
|
engine->instmem.unbind = nv04_instmem_unbind;
|
|
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
|
|
- engine->instmem.finish_access = nv04_instmem_finish_access;
|
|
+ engine->instmem.flush = nv04_instmem_flush;
|
|
engine->mc.init = nv40_mc_init;
|
|
engine->mc.takedown = nv40_mc_takedown;
|
|
engine->timer.init = nv04_timer_init;
|
|
@@ -271,8 +266,7 @@ 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;
|
|
+ engine->instmem.flush = nv50_instmem_flush;
|
|
engine->mc.init = nv50_mc_init;
|
|
engine->mc.takedown = nv50_mc_takedown;
|
|
engine->timer.init = nv04_timer_init;
|
|
@@ -404,11 +398,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);
|
|
@@ -418,15 +407,12 @@ nouveau_card_init(struct drm_device *dev)
|
|
if (ret)
|
|
goto out;
|
|
engine = &dev_priv->engine;
|
|
- dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
|
|
spin_lock_init(&dev_priv->context_switch_lock);
|
|
|
|
/* Parse BIOS tables / Run init tables if card not POSTed */
|
|
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
|
- ret = nouveau_bios_init(dev);
|
|
- if (ret)
|
|
- goto out;
|
|
- }
|
|
+ ret = nouveau_bios_init(dev);
|
|
+ if (ret)
|
|
+ goto out;
|
|
|
|
ret = nouveau_mem_detect(dev);
|
|
if (ret)
|
|
@@ -482,12 +468,19 @@ nouveau_card_init(struct drm_device *dev)
|
|
goto out_graph;
|
|
}
|
|
|
|
+ if (dev_priv->card_type >= NV_50)
|
|
+ ret = nv50_display_create(dev);
|
|
+ else
|
|
+ ret = nv04_display_create(dev);
|
|
+ if (ret)
|
|
+ goto out_fifo;
|
|
+
|
|
/* this call irq_preinstall, register irq handler and
|
|
* call irq_postinstall
|
|
*/
|
|
ret = drm_irq_install(dev);
|
|
if (ret)
|
|
- goto out_fifo;
|
|
+ goto out_display;
|
|
|
|
ret = drm_vblank_init(dev, 0);
|
|
if (ret)
|
|
@@ -501,33 +494,20 @@ 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);
|
|
-
|
|
+ nouveau_fbcon_init(dev);
|
|
return 0;
|
|
|
|
-out_channel:
|
|
- if (dev_priv->channel) {
|
|
- nouveau_channel_free(dev_priv->channel);
|
|
- dev_priv->channel = NULL;
|
|
- }
|
|
out_irq:
|
|
drm_irq_uninstall(dev);
|
|
+out_display:
|
|
+ if (dev_priv->card_type >= NV_50)
|
|
+ nv50_display_destroy(dev);
|
|
+ else
|
|
+ nv04_display_destroy(dev);
|
|
out_fifo:
|
|
if (!nouveau_noaccel)
|
|
engine->fifo.takedown(dev);
|
|
@@ -561,45 +541,37 @@ static void nouveau_card_takedown(struct drm_device *dev)
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_engine *engine = &dev_priv->engine;
|
|
|
|
- NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
|
|
-
|
|
- 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->mc.takedown(dev);
|
|
|
|
- nouveau_gpuobj_takedown(dev);
|
|
- nouveau_mem_close(dev);
|
|
- engine->instmem.takedown(dev);
|
|
+ mutex_lock(&dev->struct_mutex);
|
|
+ ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
|
|
+ ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
|
|
+ mutex_unlock(&dev->struct_mutex);
|
|
+ nouveau_sgdma_takedown(dev);
|
|
|
|
- if (drm_core_check_feature(dev, DRIVER_MODESET))
|
|
- drm_irq_uninstall(dev);
|
|
+ nouveau_gpuobj_takedown(dev);
|
|
+ nouveau_mem_close(dev);
|
|
+ engine->instmem.takedown(dev);
|
|
|
|
- nouveau_gpuobj_late_takedown(dev);
|
|
- nouveau_bios_takedown(dev);
|
|
+ drm_irq_uninstall(dev);
|
|
|
|
- vga_client_register(dev->pdev, NULL, NULL, NULL);
|
|
+ nouveau_gpuobj_late_takedown(dev);
|
|
+ nouveau_bios_takedown(dev);
|
|
|
|
- dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
|
|
- }
|
|
+ vga_client_register(dev->pdev, NULL, NULL, NULL);
|
|
}
|
|
|
|
/* here a client dies, release the stuff that was allocated for its
|
|
@@ -686,6 +658,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
|
|
struct drm_nouveau_private *dev_priv;
|
|
uint32_t reg0;
|
|
resource_size_t mmio_start_offs;
|
|
+ int ret;
|
|
|
|
dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
|
|
if (!dev_priv)
|
|
@@ -694,7 +667,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
|
|
dev_priv->dev = dev;
|
|
|
|
dev_priv->flags = flags & NOUVEAU_FLAGS;
|
|
- dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
|
|
|
|
NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
|
|
dev->pci_vendor, dev->pci_device, dev->pdev->class);
|
|
@@ -768,11 +740,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
|
|
NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
|
|
dev_priv->card_type, reg0);
|
|
|
|
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
|
- int ret = nouveau_remove_conflicting_drivers(dev);
|
|
- if (ret)
|
|
- return ret;
|
|
- }
|
|
+ ret = nouveau_remove_conflicting_drivers(dev);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
/* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
|
|
if (dev_priv->card_type >= NV_40) {
|
|
@@ -807,45 +777,27 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
|
|
dev_priv->flags |= NV_NFORCE2;
|
|
|
|
/* For kernel modesetting, init card now and bring up fbcon */
|
|
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
|
- int ret = nouveau_card_init(dev);
|
|
- if (ret)
|
|
- return ret;
|
|
- }
|
|
+ ret = nouveau_card_init(dev);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
-static void nouveau_close(struct drm_device *dev)
|
|
-{
|
|
- struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
-
|
|
- /* In the case of an error dev_priv may not be allocated yet */
|
|
- if (dev_priv)
|
|
- nouveau_card_takedown(dev);
|
|
-}
|
|
-
|
|
-/* KMS: we need mmio at load time, not when the first drm client opens. */
|
|
void nouveau_lastclose(struct drm_device *dev)
|
|
{
|
|
- if (drm_core_check_feature(dev, DRIVER_MODESET))
|
|
- return;
|
|
-
|
|
- nouveau_close(dev);
|
|
}
|
|
|
|
int nouveau_unload(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
|
|
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
|
- nouveau_fbcon_fini(dev);
|
|
- if (dev_priv->card_type >= NV_50)
|
|
- nv50_display_destroy(dev);
|
|
- else
|
|
- nv04_display_destroy(dev);
|
|
- nouveau_close(dev);
|
|
- }
|
|
+ nouveau_fbcon_fini(dev);
|
|
+ if (dev_priv->card_type >= NV_50)
|
|
+ nv50_display_destroy(dev);
|
|
+ else
|
|
+ nv04_display_destroy(dev);
|
|
+ nouveau_card_takedown(dev);
|
|
|
|
iounmap(dev_priv->mmio);
|
|
iounmap(dev_priv->ramin);
|
|
@@ -861,8 +813,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;
|
|
@@ -931,8 +881,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
|
|
{
|
|
struct drm_nouveau_setparam *setparam = data;
|
|
|
|
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
|
|
-
|
|
switch (setparam->param) {
|
|
default:
|
|
NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);
|
|
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
|
|
index 1cb19e3..2d0fee5 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
|
|
@@ -261,12 +261,11 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
|
|
|
|
saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);
|
|
head = (saved_routput & 0x100) >> 8;
|
|
-#if 0
|
|
- /* if there's a spare crtc, using it will minimise flicker for the case
|
|
- * where the in-use crtc is in use by an off-chip tmds encoder */
|
|
- if (xf86_config->crtc[head]->enabled && !xf86_config->crtc[head ^ 1]->enabled)
|
|
+
|
|
+ /* if there's a spare crtc, using it will minimise flicker */
|
|
+ if (!(NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX) & 0xC0))
|
|
head ^= 1;
|
|
-#endif
|
|
+
|
|
/* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */
|
|
routput = (saved_routput & 0xfffffece) | head << 8;
|
|
|
|
@@ -315,9 +314,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
|
|
{
|
|
struct drm_device *dev = encoder->dev;
|
|
struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
|
|
- uint32_t sample = nv17_dac_sample_load(encoder);
|
|
|
|
- if (sample & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
|
|
+ if (nv04_dac_in_use(encoder))
|
|
+ return connector_status_disconnected;
|
|
+
|
|
+ if (nv17_dac_sample_load(encoder) &
|
|
+ NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
|
|
NV_INFO(dev, "Load detected on output %c\n",
|
|
'@' + ffs(dcb->or));
|
|
return connector_status_connected;
|
|
@@ -330,6 +332,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder,
|
|
struct drm_display_mode *mode,
|
|
struct drm_display_mode *adjusted_mode)
|
|
{
|
|
+ if (nv04_dac_in_use(encoder))
|
|
+ return false;
|
|
+
|
|
return true;
|
|
}
|
|
|
|
@@ -428,6 +433,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable)
|
|
}
|
|
}
|
|
|
|
+/* Check if the DAC corresponding to 'encoder' is being used by
|
|
+ * someone else. */
|
|
+bool nv04_dac_in_use(struct drm_encoder *encoder)
|
|
+{
|
|
+ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
|
|
+ struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
|
|
+
|
|
+ return nv_gf4_disp_arch(encoder->dev) &&
|
|
+ (dev_priv->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index));
|
|
+}
|
|
+
|
|
static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)
|
|
{
|
|
struct drm_device *dev = encoder->dev;
|
|
@@ -501,11 +517,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = {
|
|
.destroy = nv04_dac_destroy,
|
|
};
|
|
|
|
-int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
+int
|
|
+nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
|
|
{
|
|
const struct drm_encoder_helper_funcs *helper;
|
|
- struct drm_encoder *encoder;
|
|
struct nouveau_encoder *nv_encoder = NULL;
|
|
+ struct drm_device *dev = connector->dev;
|
|
+ struct drm_encoder *encoder;
|
|
|
|
nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
|
|
if (!nv_encoder)
|
|
@@ -527,5 +545,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
encoder->possible_crtcs = entry->heads;
|
|
encoder->possible_clones = 0;
|
|
|
|
+ drm_mode_connector_attach_encoder(connector, encoder);
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
|
|
index 41634d4..3311f3a 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
|
|
@@ -413,10 +413,6 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
|
|
struct dcb_entry *dcbe = nv_encoder->dcb;
|
|
int head = nouveau_crtc(encoder->crtc)->index;
|
|
|
|
- NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
|
|
- drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
|
|
- nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
|
|
-
|
|
if (dcbe->type == OUTPUT_TMDS)
|
|
run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock);
|
|
else if (dcbe->type == OUTPUT_LVDS)
|
|
@@ -584,11 +580,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = {
|
|
.destroy = nv04_dfp_destroy,
|
|
};
|
|
|
|
-int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
+int
|
|
+nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry)
|
|
{
|
|
const struct drm_encoder_helper_funcs *helper;
|
|
- struct drm_encoder *encoder;
|
|
struct nouveau_encoder *nv_encoder = NULL;
|
|
+ struct drm_encoder *encoder;
|
|
int type;
|
|
|
|
switch (entry->type) {
|
|
@@ -613,11 +610,12 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
nv_encoder->dcb = entry;
|
|
nv_encoder->or = ffs(entry->or) - 1;
|
|
|
|
- drm_encoder_init(dev, encoder, &nv04_dfp_funcs, type);
|
|
+ drm_encoder_init(connector->dev, encoder, &nv04_dfp_funcs, type);
|
|
drm_encoder_helper_add(encoder, helper);
|
|
|
|
encoder->possible_crtcs = entry->heads;
|
|
encoder->possible_clones = 0;
|
|
|
|
+ drm_mode_connector_attach_encoder(connector, encoder);
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
|
|
index c7898b4..b35b7ed 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv04_display.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
|
|
@@ -94,6 +94,7 @@ 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;
|
|
@@ -132,19 +133,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,8 +160,14 @@ 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);
|
|
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
|
|
index 66fe559..06cedd9 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv04_fifo.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
|
|
@@ -112,6 +112,12 @@ nv04_fifo_channel_id(struct drm_device *dev)
|
|
NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
|
|
}
|
|
|
|
+#ifdef __BIG_ENDIAN
|
|
+#define DMA_FETCH_ENDIANNESS NV_PFIFO_CACHE1_BIG_ENDIAN
|
|
+#else
|
|
+#define DMA_FETCH_ENDIANNESS 0
|
|
+#endif
|
|
+
|
|
int
|
|
nv04_fifo_create_context(struct nouveau_channel *chan)
|
|
{
|
|
@@ -131,18 +137,13 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
|
|
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
|
|
|
/* Setup initial state */
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
RAMFC_WR(DMA_PUT, chan->pushbuf_base);
|
|
RAMFC_WR(DMA_GET, chan->pushbuf_base);
|
|
RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
|
|
RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
|
|
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
|
|
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
|
|
-#ifdef __BIG_ENDIAN
|
|
- NV_PFIFO_CACHE1_BIG_ENDIAN |
|
|
-#endif
|
|
- 0));
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ DMA_FETCH_ENDIANNESS));
|
|
|
|
/* enable the fifo dma operation */
|
|
nv_wr32(dev, NV04_PFIFO_MODE,
|
|
@@ -169,8 +170,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
uint32_t fc = NV04_RAMFC(chid), tmp;
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, false);
|
|
-
|
|
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
|
|
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
|
|
tmp = nv_ri32(dev, fc + 8);
|
|
@@ -181,8 +180,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
|
|
nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20));
|
|
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24));
|
|
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
-
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
|
|
}
|
|
@@ -223,7 +220,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
|
|
return -EINVAL;
|
|
}
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
|
|
RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
|
|
tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16;
|
|
@@ -233,7 +229,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
|
|
RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH));
|
|
RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
|
|
RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
|
|
nv04_fifo_do_load_context(dev, pfifo->channels - 1);
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
|
|
@@ -297,6 +292,7 @@ nv04_fifo_init(struct drm_device *dev)
|
|
|
|
nv04_fifo_init_intr(dev);
|
|
pfifo->enable(dev);
|
|
+ pfifo->reassign(dev, true);
|
|
|
|
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
|
|
if (dev_priv->fifos[i]) {
|
|
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
|
|
index 618355e..c897342 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
|
|
@@ -342,7 +342,7 @@ static uint32_t nv04_graph_ctx_regs[] = {
|
|
};
|
|
|
|
struct graph_state {
|
|
- int nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
|
|
+ uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
|
|
};
|
|
|
|
struct nouveau_channel *
|
|
@@ -527,8 +527,7 @@ static int
|
|
nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass,
|
|
int mthd, uint32_t data)
|
|
{
|
|
- chan->fence.last_sequence_irq = data;
|
|
- nouveau_fence_handler(chan->dev, chan->id);
|
|
+ atomic_set(&chan->fence.last_sequence_irq, data);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
|
|
index a3b9563..4408232 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv04_instmem.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
|
|
@@ -49,10 +49,8 @@ nv04_instmem_determine_amount(struct drm_device *dev)
|
|
NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
|
|
|
|
/* Clear all of it, except the BIOS image that's in the first 64KiB */
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
|
|
nv_wi32(dev, i, 0x00000000);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
}
|
|
|
|
static void
|
|
@@ -106,7 +104,7 @@ int nv04_instmem_init(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
uint32_t offset;
|
|
- int ret = 0;
|
|
+ int ret;
|
|
|
|
nv04_instmem_determine_amount(dev);
|
|
nv04_instmem_configure_fixed_tables(dev);
|
|
@@ -129,14 +127,14 @@ int nv04_instmem_init(struct drm_device *dev)
|
|
offset = 0x40000;
|
|
}
|
|
|
|
- ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
|
|
- offset, dev_priv->ramin_rsvd_vram - offset);
|
|
+ ret = drm_mm_init(&dev_priv->ramin_heap, offset,
|
|
+ dev_priv->ramin_rsvd_vram - offset);
|
|
if (ret) {
|
|
- dev_priv->ramin_heap = NULL;
|
|
- NV_ERROR(dev, "Failed to init RAMIN heap\n");
|
|
+ NV_ERROR(dev, "Failed to init RAMIN heap: %d\n", ret);
|
|
+ return ret;
|
|
}
|
|
|
|
- return ret;
|
|
+ return 0;
|
|
}
|
|
|
|
void
|
|
@@ -186,12 +184,7 @@ nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
|
|
}
|
|
|
|
void
|
|
-nv04_instmem_prepare_access(struct drm_device *dev, bool write)
|
|
-{
|
|
-}
|
|
-
|
|
-void
|
|
-nv04_instmem_finish_access(struct drm_device *dev)
|
|
+nv04_instmem_flush(struct drm_device *dev)
|
|
{
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nv04_mc.c b/drivers/gpu/drm/nouveau/nv04_mc.c
|
|
index 617ed1e..2af43a1 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv04_mc.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv04_mc.c
|
|
@@ -11,6 +11,10 @@ nv04_mc_init(struct drm_device *dev)
|
|
*/
|
|
|
|
nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF);
|
|
+
|
|
+ /* Disable PROM access. */
|
|
+ nv_wr32(dev, NV_PBUS_PCI_NV_20, NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
|
|
index c4e3404..84b5954 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
|
|
@@ -223,10 +223,12 @@ static void nv04_tv_destroy(struct drm_encoder *encoder)
|
|
kfree(nv_encoder);
|
|
}
|
|
|
|
-int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
+int
|
|
+nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
|
|
{
|
|
struct nouveau_encoder *nv_encoder;
|
|
struct drm_encoder *encoder;
|
|
+ struct drm_device *dev = connector->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct i2c_adapter *adap;
|
|
struct drm_encoder_funcs *funcs = NULL;
|
|
@@ -266,7 +268,7 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
|
|
was_locked = NVLockVgaCrtcs(dev, false);
|
|
|
|
- ret = drm_i2c_encoder_init(encoder->dev, to_encoder_slave(encoder), adap,
|
|
+ ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), adap,
|
|
&nv04_tv_encoder_info[type].board_info);
|
|
|
|
NVLockVgaCrtcs(dev, was_locked);
|
|
@@ -294,7 +296,9 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
|
|
/* Set the slave encoder configuration */
|
|
sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params);
|
|
+ sfuncs->create_resources(encoder, connector);
|
|
|
|
+ drm_mode_connector_attach_encoder(connector, encoder);
|
|
return 0;
|
|
|
|
fail:
|
|
diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c
|
|
index 7aeabf2..7a4069c 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv10_fifo.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv10_fifo.c
|
|
@@ -55,7 +55,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
|
|
/* Fill entries that are seen filled in dumps of nvidia driver just
|
|
* after channel's is put into DMA mode
|
|
*/
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
nv_wi32(dev, fc + 0, chan->pushbuf_base);
|
|
nv_wi32(dev, fc + 4, chan->pushbuf_base);
|
|
nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
|
|
@@ -66,7 +65,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
|
|
NV_PFIFO_CACHE1_BIG_ENDIAN |
|
|
#endif
|
|
0);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
|
|
/* enable the fifo dma operation */
|
|
nv_wr32(dev, NV04_PFIFO_MODE,
|
|
@@ -91,8 +89,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
uint32_t fc = NV10_RAMFC(chid), tmp;
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, false);
|
|
-
|
|
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
|
|
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
|
|
nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
|
|
@@ -117,8 +113,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
|
|
nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 48));
|
|
|
|
out:
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
-
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
|
|
}
|
|
@@ -155,8 +149,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
|
|
return 0;
|
|
fc = NV10_RAMFC(chid);
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
-
|
|
nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
|
|
nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
|
|
nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
|
|
@@ -179,8 +171,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
|
|
nv_wi32(dev, fc + 48, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
|
|
|
|
out:
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
-
|
|
nv10_fifo_do_load_context(dev, pfifo->channels - 1);
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
|
|
return 0;
|
|
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
|
|
index 74c8803..359506e 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv17_tv.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv17_tv.c
|
|
@@ -116,6 +116,20 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
|
|
return sample;
|
|
}
|
|
|
|
+static bool
|
|
+get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask)
|
|
+{
|
|
+ /* Zotac FX5200 */
|
|
+ if ((dev->pdev->device == 0x0322) &&
|
|
+ (dev->pdev->subsystem_vendor == 0x19da) &&
|
|
+ (dev->pdev->subsystem_device == 0x2035)) {
|
|
+ *pin_mask = 0xc;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
static enum drm_connector_status
|
|
nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
|
|
{
|
|
@@ -124,12 +138,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 +176,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 +320,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
|
|
{
|
|
struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
|
|
|
|
+ if (nv04_dac_in_use(encoder))
|
|
+ return false;
|
|
+
|
|
if (tv_norm->kind == CTV_ENC_MODE)
|
|
adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock;
|
|
else
|
|
@@ -744,8 +771,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 +803,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
encoder->possible_crtcs = entry->heads;
|
|
encoder->possible_clones = 0;
|
|
|
|
+ nv17_tv_create_resources(encoder, connector);
|
|
+ drm_mode_connector_attach_encoder(connector, encoder);
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
|
|
index d6fc0a8..191c15c 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
|
|
@@ -370,68 +370,54 @@ nv20_graph_create_context(struct nouveau_channel *chan)
|
|
{
|
|
struct drm_device *dev = chan->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
|
|
- unsigned int ctx_size;
|
|
unsigned int idoffs = 0x28/4;
|
|
int ret;
|
|
|
|
switch (dev_priv->chipset) {
|
|
case 0x20:
|
|
- ctx_size = NV20_GRCTX_SIZE;
|
|
ctx_init = nv20_graph_context_init;
|
|
idoffs = 0;
|
|
break;
|
|
case 0x25:
|
|
case 0x28:
|
|
- ctx_size = NV25_GRCTX_SIZE;
|
|
ctx_init = nv25_graph_context_init;
|
|
break;
|
|
case 0x2a:
|
|
- ctx_size = NV2A_GRCTX_SIZE;
|
|
ctx_init = nv2a_graph_context_init;
|
|
idoffs = 0;
|
|
break;
|
|
case 0x30:
|
|
case 0x31:
|
|
- ctx_size = NV30_31_GRCTX_SIZE;
|
|
ctx_init = nv30_31_graph_context_init;
|
|
break;
|
|
case 0x34:
|
|
- ctx_size = NV34_GRCTX_SIZE;
|
|
ctx_init = nv34_graph_context_init;
|
|
break;
|
|
case 0x35:
|
|
case 0x36:
|
|
- ctx_size = NV35_36_GRCTX_SIZE;
|
|
ctx_init = nv35_36_graph_context_init;
|
|
break;
|
|
default:
|
|
- ctx_size = 0;
|
|
- ctx_init = nv35_36_graph_context_init;
|
|
- NV_ERROR(dev, "Please contact the devs if you want your NV%x"
|
|
- " card to work\n", dev_priv->chipset);
|
|
- return -ENOSYS;
|
|
- break;
|
|
+ BUG_ON(1);
|
|
}
|
|
|
|
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16,
|
|
- NVOBJ_FLAG_ZERO_ALLOC,
|
|
- &chan->ramin_grctx);
|
|
+ ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
|
|
+ 16, NVOBJ_FLAG_ZERO_ALLOC,
|
|
+ &chan->ramin_grctx);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* Initialise default context values */
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
ctx_init(dev, chan->ramin_grctx->gpuobj);
|
|
|
|
/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
|
|
nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs,
|
|
(chan->id << 24) | 0x1); /* CTX_USER */
|
|
|
|
- nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id,
|
|
- chan->ramin_grctx->instance >> 4);
|
|
-
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id,
|
|
+ chan->ramin_grctx->instance >> 4);
|
|
return 0;
|
|
}
|
|
|
|
@@ -440,13 +426,12 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
|
|
{
|
|
struct drm_device *dev = chan->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
|
|
if (chan->ramin_grctx)
|
|
nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
- nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0);
|
|
}
|
|
|
|
int
|
|
@@ -538,29 +523,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
|
|
int
|
|
nv20_graph_init(struct drm_device *dev)
|
|
{
|
|
- struct drm_nouveau_private *dev_priv =
|
|
- (struct drm_nouveau_private *)dev->dev_private;
|
|
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
uint32_t tmp, vramsz;
|
|
int ret, i;
|
|
|
|
+ switch (dev_priv->chipset) {
|
|
+ case 0x20:
|
|
+ pgraph->grctx_size = NV20_GRCTX_SIZE;
|
|
+ break;
|
|
+ case 0x25:
|
|
+ case 0x28:
|
|
+ pgraph->grctx_size = NV25_GRCTX_SIZE;
|
|
+ break;
|
|
+ case 0x2a:
|
|
+ pgraph->grctx_size = NV2A_GRCTX_SIZE;
|
|
+ break;
|
|
+ default:
|
|
+ NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
|
|
+ pgraph->accel_blocked = true;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
nv_wr32(dev, NV03_PMC_ENABLE,
|
|
nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
|
|
nv_wr32(dev, NV03_PMC_ENABLE,
|
|
nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
|
|
|
|
- if (!dev_priv->ctx_table) {
|
|
+ if (!pgraph->ctx_table) {
|
|
/* Create Context Pointer Table */
|
|
- dev_priv->ctx_table_size = 32 * 4;
|
|
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
|
|
- dev_priv->ctx_table_size, 16,
|
|
+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
|
|
NVOBJ_FLAG_ZERO_ALLOC,
|
|
- &dev_priv->ctx_table);
|
|
+ &pgraph->ctx_table);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
|
|
- dev_priv->ctx_table->instance >> 4);
|
|
+ pgraph->ctx_table->instance >> 4);
|
|
|
|
nv20_graph_rdi(dev);
|
|
|
|
@@ -644,34 +644,52 @@ void
|
|
nv20_graph_takedown(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
|
|
- nouveau_gpuobj_ref_del(dev, &dev_priv->ctx_table);
|
|
+ nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table);
|
|
}
|
|
|
|
int
|
|
nv30_graph_init(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
int ret, i;
|
|
|
|
+ switch (dev_priv->chipset) {
|
|
+ case 0x30:
|
|
+ case 0x31:
|
|
+ pgraph->grctx_size = NV30_31_GRCTX_SIZE;
|
|
+ break;
|
|
+ case 0x34:
|
|
+ pgraph->grctx_size = NV34_GRCTX_SIZE;
|
|
+ break;
|
|
+ case 0x35:
|
|
+ case 0x36:
|
|
+ pgraph->grctx_size = NV35_36_GRCTX_SIZE;
|
|
+ break;
|
|
+ default:
|
|
+ NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
|
|
+ pgraph->accel_blocked = true;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
nv_wr32(dev, NV03_PMC_ENABLE,
|
|
nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
|
|
nv_wr32(dev, NV03_PMC_ENABLE,
|
|
nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
|
|
|
|
- if (!dev_priv->ctx_table) {
|
|
+ if (!pgraph->ctx_table) {
|
|
/* Create Context Pointer Table */
|
|
- dev_priv->ctx_table_size = 32 * 4;
|
|
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
|
|
- dev_priv->ctx_table_size, 16,
|
|
+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
|
|
NVOBJ_FLAG_ZERO_ALLOC,
|
|
- &dev_priv->ctx_table);
|
|
+ &pgraph->ctx_table);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
|
|
- dev_priv->ctx_table->instance >> 4);
|
|
+ pgraph->ctx_table->instance >> 4);
|
|
|
|
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
|
|
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
|
|
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
|
|
index 500ccfd..2b67f18 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
|
|
@@ -48,7 +48,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
|
|
|
|
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
nv_wi32(dev, fc + 0, chan->pushbuf_base);
|
|
nv_wi32(dev, fc + 4, chan->pushbuf_base);
|
|
nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
|
|
@@ -61,7 +60,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
|
|
0x30000000 /* no idea.. */);
|
|
nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
|
|
nv_wi32(dev, fc + 60, 0x0001FFFF);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
|
|
/* enable the fifo dma operation */
|
|
nv_wr32(dev, NV04_PFIFO_MODE,
|
|
@@ -89,8 +87,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
uint32_t fc = NV40_RAMFC(chid), tmp, tmp2;
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, false);
|
|
-
|
|
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
|
|
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
|
|
nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
|
|
@@ -127,8 +123,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
|
|
nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
|
|
nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
|
|
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
-
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
|
|
}
|
|
@@ -166,7 +160,6 @@ nv40_fifo_unload_context(struct drm_device *dev)
|
|
return 0;
|
|
fc = NV40_RAMFC(chid);
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
|
|
nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
|
|
nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
|
|
@@ -200,7 +193,6 @@ nv40_fifo_unload_context(struct drm_device *dev)
|
|
tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
|
|
nv_wi32(dev, fc + 72, tmp);
|
|
#endif
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
|
|
nv40_fifo_do_load_context(dev, pfifo->channels - 1);
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
|
|
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
|
|
index 704a25d..ef550ce 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
|
|
@@ -58,6 +58,7 @@ nv40_graph_create_context(struct nouveau_channel *chan)
|
|
struct drm_device *dev = chan->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
+ struct nouveau_grctx ctx = {};
|
|
int ret;
|
|
|
|
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
|
|
@@ -67,20 +68,13 @@ nv40_graph_create_context(struct nouveau_channel *chan)
|
|
return ret;
|
|
|
|
/* Initialise default context values */
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
- if (!pgraph->ctxprog) {
|
|
- struct nouveau_grctx ctx = {};
|
|
-
|
|
- ctx.dev = chan->dev;
|
|
- ctx.mode = NOUVEAU_GRCTX_VALS;
|
|
- ctx.data = chan->ramin_grctx->gpuobj;
|
|
- nv40_grctx_init(&ctx);
|
|
- } else {
|
|
- nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj);
|
|
- }
|
|
+ ctx.dev = chan->dev;
|
|
+ ctx.mode = NOUVEAU_GRCTX_VALS;
|
|
+ ctx.data = chan->ramin_grctx->gpuobj;
|
|
+ nv40_grctx_init(&ctx);
|
|
+
|
|
nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
|
|
chan->ramin_grctx->gpuobj->im_pramin->start);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
return 0;
|
|
}
|
|
|
|
@@ -238,7 +232,8 @@ nv40_graph_init(struct drm_device *dev)
|
|
struct drm_nouveau_private *dev_priv =
|
|
(struct drm_nouveau_private *)dev->dev_private;
|
|
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
|
|
- uint32_t vramsz;
|
|
+ struct nouveau_grctx ctx = {};
|
|
+ uint32_t vramsz, *cp;
|
|
int i, j;
|
|
|
|
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
|
|
@@ -246,32 +241,22 @@ nv40_graph_init(struct drm_device *dev)
|
|
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
|
|
NV_PMC_ENABLE_PGRAPH);
|
|
|
|
- if (nouveau_ctxfw) {
|
|
- nouveau_grctx_prog_load(dev);
|
|
- dev_priv->engine.graph.grctx_size = 175 * 1024;
|
|
- }
|
|
+ cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
|
|
+ if (!cp)
|
|
+ return -ENOMEM;
|
|
|
|
- if (!dev_priv->engine.graph.ctxprog) {
|
|
- struct nouveau_grctx ctx = {};
|
|
- uint32_t *cp;
|
|
+ ctx.dev = dev;
|
|
+ ctx.mode = NOUVEAU_GRCTX_PROG;
|
|
+ ctx.data = cp;
|
|
+ ctx.ctxprog_max = 256;
|
|
+ nv40_grctx_init(&ctx);
|
|
+ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
|
|
|
|
- cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
|
|
- if (!cp)
|
|
- return -ENOMEM;
|
|
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
|
|
+ for (i = 0; i < ctx.ctxprog_len; i++)
|
|
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
|
|
|
|
- ctx.dev = dev;
|
|
- ctx.mode = NOUVEAU_GRCTX_PROG;
|
|
- ctx.data = cp;
|
|
- ctx.ctxprog_max = 256;
|
|
- nv40_grctx_init(&ctx);
|
|
- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
|
|
-
|
|
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
|
|
- for (i = 0; i < ctx.ctxprog_len; i++)
|
|
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
|
|
-
|
|
- kfree(cp);
|
|
- }
|
|
+ kfree(cp);
|
|
|
|
/* No context present currently */
|
|
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
|
|
@@ -407,7 +392,6 @@ nv40_graph_init(struct drm_device *dev)
|
|
|
|
void nv40_graph_takedown(struct drm_device *dev)
|
|
{
|
|
- nouveau_grctx_fini(dev);
|
|
}
|
|
|
|
struct nouveau_pgraph_object_class nv40_graph_grclass[] = {
|
|
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
|
|
index b4e4a3b..5d11ea1 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
|
|
@@ -440,47 +440,15 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
|
|
{
|
|
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
|
struct drm_device *dev = crtc->dev;
|
|
- struct drm_encoder *encoder;
|
|
- uint32_t dac = 0, sor = 0;
|
|
|
|
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
|
|
|
|
- /* Disconnect all unused encoders. */
|
|
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
|
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
|
-
|
|
- if (!drm_helper_encoder_in_use(encoder))
|
|
- continue;
|
|
-
|
|
- if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
|
|
- nv_encoder->dcb->type == OUTPUT_TV)
|
|
- dac |= (1 << nv_encoder->or);
|
|
- else
|
|
- sor |= (1 << nv_encoder->or);
|
|
- }
|
|
-
|
|
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
|
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
|
-
|
|
- if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
|
|
- nv_encoder->dcb->type == OUTPUT_TV) {
|
|
- if (dac & (1 << nv_encoder->or))
|
|
- continue;
|
|
- } else {
|
|
- if (sor & (1 << nv_encoder->or))
|
|
- continue;
|
|
- }
|
|
-
|
|
- nv_encoder->disconnect(nv_encoder);
|
|
- }
|
|
-
|
|
nv50_crtc_blank(nv_crtc, true);
|
|
}
|
|
|
|
static void
|
|
nv50_crtc_commit(struct drm_crtc *crtc)
|
|
{
|
|
- struct drm_crtc *crtc2;
|
|
struct drm_device *dev = crtc->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_channel *evo = dev_priv->evo;
|
|
@@ -491,20 +459,14 @@ nv50_crtc_commit(struct drm_crtc *crtc)
|
|
|
|
nv50_crtc_blank(nv_crtc, false);
|
|
|
|
- /* Explicitly blank all unused crtc's. */
|
|
- list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) {
|
|
- if (!drm_helper_crtc_in_use(crtc2))
|
|
- nv50_crtc_blank(nouveau_crtc(crtc2), true);
|
|
- }
|
|
-
|
|
ret = RING_SPACE(evo, 2);
|
|
if (ret) {
|
|
NV_ERROR(dev, "no space while committing crtc\n");
|
|
return;
|
|
}
|
|
BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
|
|
- OUT_RING(evo, 0);
|
|
- FIRE_RING(evo);
|
|
+ OUT_RING (evo, 0);
|
|
+ FIRE_RING (evo);
|
|
}
|
|
|
|
static bool
|
|
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
|
|
index 1fd9537..1bc0859 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
|
|
@@ -37,22 +37,31 @@
|
|
#include "nv50_display.h"
|
|
|
|
static void
|
|
-nv50_dac_disconnect(struct nouveau_encoder *nv_encoder)
|
|
+nv50_dac_disconnect(struct drm_encoder *encoder)
|
|
{
|
|
- struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
|
|
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
|
+ struct drm_device *dev = encoder->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_channel *evo = dev_priv->evo;
|
|
int ret;
|
|
|
|
+ if (!nv_encoder->crtc)
|
|
+ return;
|
|
+ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
|
|
+
|
|
NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
|
|
|
|
- ret = RING_SPACE(evo, 2);
|
|
+ ret = RING_SPACE(evo, 4);
|
|
if (ret) {
|
|
NV_ERROR(dev, "no space while disconnecting DAC\n");
|
|
return;
|
|
}
|
|
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
|
|
- OUT_RING(evo, 0);
|
|
+ OUT_RING (evo, 0);
|
|
+ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
|
|
+ OUT_RING (evo, 0);
|
|
+
|
|
+ nv_encoder->crtc = NULL;
|
|
}
|
|
|
|
static enum drm_connector_status
|
|
@@ -213,7 +222,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
uint32_t mode_ctl = 0, mode_ctl2 = 0;
|
|
int ret;
|
|
|
|
- NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
|
|
+ NV_DEBUG_KMS(dev, "or %d type %d crtc %d\n",
|
|
+ nv_encoder->or, nv_encoder->dcb->type, crtc->index);
|
|
|
|
nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
|
|
|
|
@@ -243,6 +253,14 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
|
|
OUT_RING(evo, mode_ctl);
|
|
OUT_RING(evo, mode_ctl2);
|
|
+
|
|
+ nv_encoder->crtc = encoder->crtc;
|
|
+}
|
|
+
|
|
+static struct drm_crtc *
|
|
+nv50_dac_crtc_get(struct drm_encoder *encoder)
|
|
+{
|
|
+ return nouveau_encoder(encoder)->crtc;
|
|
}
|
|
|
|
static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
|
|
@@ -253,7 +271,9 @@ static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
|
|
.prepare = nv50_dac_prepare,
|
|
.commit = nv50_dac_commit,
|
|
.mode_set = nv50_dac_mode_set,
|
|
- .detect = nv50_dac_detect
|
|
+ .get_crtc = nv50_dac_crtc_get,
|
|
+ .detect = nv50_dac_detect,
|
|
+ .disable = nv50_dac_disconnect
|
|
};
|
|
|
|
static void
|
|
@@ -275,14 +295,11 @@ static const struct drm_encoder_funcs nv50_dac_encoder_funcs = {
|
|
};
|
|
|
|
int
|
|
-nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
+nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
|
|
{
|
|
struct nouveau_encoder *nv_encoder;
|
|
struct drm_encoder *encoder;
|
|
|
|
- NV_DEBUG_KMS(dev, "\n");
|
|
- NV_INFO(dev, "Detected a DAC output\n");
|
|
-
|
|
nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
|
|
if (!nv_encoder)
|
|
return -ENOMEM;
|
|
@@ -291,14 +308,14 @@ nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
nv_encoder->dcb = entry;
|
|
nv_encoder->or = ffs(entry->or) - 1;
|
|
|
|
- nv_encoder->disconnect = nv50_dac_disconnect;
|
|
-
|
|
- drm_encoder_init(dev, encoder, &nv50_dac_encoder_funcs,
|
|
+ drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
|
|
DRM_MODE_ENCODER_DAC);
|
|
drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
|
|
|
|
encoder->possible_crtcs = entry->heads;
|
|
encoder->possible_clones = 0;
|
|
+
|
|
+ drm_mode_connector_attach_encoder(connector, encoder);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
|
|
index e6a44af..fb5f122 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv50_display.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
|
|
@@ -71,14 +71,13 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
|
|
return ret;
|
|
}
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
|
|
nv_wo32(dev, obj, 1, limit);
|
|
nv_wo32(dev, obj, 2, offset);
|
|
nv_wo32(dev, obj, 3, 0x00000000);
|
|
nv_wo32(dev, obj, 4, 0x00000000);
|
|
nv_wo32(dev, obj, 5, 0x00010000);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
|
|
return 0;
|
|
}
|
|
@@ -110,8 +109,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
|
|
return ret;
|
|
}
|
|
|
|
- ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj->
|
|
- im_pramin->start, 32768);
|
|
+ ret = drm_mm_init(&chan->ramin_heap,
|
|
+ chan->ramin->gpuobj->im_pramin->start, 32768);
|
|
if (ret) {
|
|
NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
|
|
nv50_evo_channel_del(pchan);
|
|
@@ -185,7 +184,7 @@ nv50_display_init(struct drm_device *dev)
|
|
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
|
|
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 +365,10 @@ 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]);
|
|
+ nv50_gpio_irq_enable(dev, conn->dcb->gpio_tag, true);
|
|
}
|
|
|
|
return 0;
|
|
@@ -465,6 +448,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 +491,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 +510,13 @@ int nv50_display_create(struct drm_device *dev)
|
|
}
|
|
}
|
|
|
|
- for (i = 0 ; i < dcb->connector.entries; i++) {
|
|
- if (i != 0 && dcb->connector.entry[i].index2 ==
|
|
- dcb->connector.entry[i - 1].index2)
|
|
- continue;
|
|
- nouveau_connector_create(dev, &dcb->connector.entry[i]);
|
|
+ list_for_each_entry_safe(connector, ct,
|
|
+ &dev->mode_config.connector_list, head) {
|
|
+ if (!connector->encoder_ids[0]) {
|
|
+ NV_WARN(dev, "%s has no encoders, removing\n",
|
|
+ drm_get_connector_name(connector));
|
|
+ connector->funcs->destroy(connector);
|
|
+ }
|
|
}
|
|
|
|
ret = nv50_display_init(dev);
|
|
@@ -552,131 +542,28 @@ int nv50_display_destroy(struct drm_device *dev)
|
|
return 0;
|
|
}
|
|
|
|
-static inline uint32_t
|
|
-nv50_display_mode_ctrl(struct drm_device *dev, bool sor, int or)
|
|
-{
|
|
- struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- uint32_t mc;
|
|
-
|
|
- if (sor) {
|
|
- if (dev_priv->chipset < 0x90 ||
|
|
- dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0)
|
|
- mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(or));
|
|
- else
|
|
- mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(or));
|
|
- } else {
|
|
- mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(or));
|
|
- }
|
|
-
|
|
- return mc;
|
|
-}
|
|
-
|
|
-static int
|
|
-nv50_display_irq_head(struct drm_device *dev, int *phead,
|
|
- struct dcb_entry **pdcbent)
|
|
-{
|
|
- struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- uint32_t unk30 = nv_rd32(dev, NV50_PDISPLAY_UNK30_CTRL);
|
|
- uint32_t dac = 0, sor = 0;
|
|
- int head, i, or = 0, type = OUTPUT_ANY;
|
|
-
|
|
- /* We're assuming that head 0 *or* head 1 will be active here,
|
|
- * and not both. I'm not sure if the hw will even signal both
|
|
- * ever, but it definitely shouldn't for us as we commit each
|
|
- * CRTC separately, and submission will be blocked by the GPU
|
|
- * until we handle each in turn.
|
|
- */
|
|
- NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
|
|
- head = ffs((unk30 >> 9) & 3) - 1;
|
|
- if (head < 0)
|
|
- return -EINVAL;
|
|
-
|
|
- /* This assumes CRTCs are never bound to multiple encoders, which
|
|
- * should be the case.
|
|
- */
|
|
- for (i = 0; i < 3 && type == OUTPUT_ANY; i++) {
|
|
- uint32_t mc = nv50_display_mode_ctrl(dev, false, i);
|
|
- if (!(mc & (1 << head)))
|
|
- continue;
|
|
-
|
|
- switch ((mc >> 8) & 0xf) {
|
|
- case 0: type = OUTPUT_ANALOG; break;
|
|
- case 1: type = OUTPUT_TV; break;
|
|
- default:
|
|
- NV_ERROR(dev, "unknown dac mode_ctrl: 0x%08x\n", dac);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- or = i;
|
|
- }
|
|
-
|
|
- for (i = 0; i < 4 && type == OUTPUT_ANY; i++) {
|
|
- uint32_t mc = nv50_display_mode_ctrl(dev, true, i);
|
|
- if (!(mc & (1 << head)))
|
|
- continue;
|
|
-
|
|
- switch ((mc >> 8) & 0xf) {
|
|
- case 0: type = OUTPUT_LVDS; break;
|
|
- case 1: type = OUTPUT_TMDS; break;
|
|
- case 2: type = OUTPUT_TMDS; break;
|
|
- case 5: type = OUTPUT_TMDS; break;
|
|
- case 8: type = OUTPUT_DP; break;
|
|
- case 9: type = OUTPUT_DP; break;
|
|
- default:
|
|
- NV_ERROR(dev, "unknown sor mode_ctrl: 0x%08x\n", sor);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- or = i;
|
|
- }
|
|
-
|
|
- NV_DEBUG_KMS(dev, "type %d, or %d\n", type, or);
|
|
- if (type == OUTPUT_ANY) {
|
|
- NV_ERROR(dev, "unknown encoder!!\n");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
|
|
- struct dcb_entry *dcbent = &dev_priv->vbios.dcb.entry[i];
|
|
-
|
|
- if (dcbent->type != type)
|
|
- continue;
|
|
-
|
|
- if (!(dcbent->or & (1 << or)))
|
|
- continue;
|
|
-
|
|
- *phead = head;
|
|
- *pdcbent = dcbent;
|
|
- return 0;
|
|
- }
|
|
-
|
|
- NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or);
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static uint32_t
|
|
-nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent,
|
|
- int pxclk)
|
|
+static u16
|
|
+nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
|
|
+ u32 mc, int pxclk)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_connector *nv_connector = NULL;
|
|
struct drm_encoder *encoder;
|
|
struct nvbios *bios = &dev_priv->vbios;
|
|
- uint32_t mc, script = 0, or;
|
|
+ u32 script = 0, or;
|
|
|
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
|
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
|
|
|
- if (nv_encoder->dcb != dcbent)
|
|
+ if (nv_encoder->dcb != dcb)
|
|
continue;
|
|
|
|
nv_connector = nouveau_encoder_connector_get(nv_encoder);
|
|
break;
|
|
}
|
|
|
|
- or = ffs(dcbent->or) - 1;
|
|
- mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or);
|
|
- switch (dcbent->type) {
|
|
+ or = ffs(dcb->or) - 1;
|
|
+ switch (dcb->type) {
|
|
case OUTPUT_LVDS:
|
|
script = (mc >> 8) & 0xf;
|
|
if (bios->fp_no_ddc) {
|
|
@@ -767,17 +654,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 +775,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;
|
|
+
|
|
+ /* 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;
|
|
+
|
|
+ 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;
|
|
+ }
|
|
|
|
- NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, 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));
|
|
|
|
- if (dcbent->type != OUTPUT_DP)
|
|
- nouveau_bios_run_display_table(dev, dcbent, 0, -2);
|
|
+ NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
|
|
+ if (!(mc & (1 << crtc)))
|
|
+ continue;
|
|
|
|
- nv50_crtc_set_clock(dev, head, pclk);
|
|
+ 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;
|
|
+ }
|
|
|
|
- nouveau_bios_run_display_table(dev, dcbent, script, pclk);
|
|
+ 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;
|
|
+ }
|
|
|
|
- nv50_display_unk20_dp_hack(dev, dcbent);
|
|
+ script = nv50_display_script_select(dev, dcb, mc, pclk);
|
|
+ nouveau_bios_run_display_table(dev, dcb, script, pclk);
|
|
|
|
- tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
|
|
- tmp &= ~0x000000f;
|
|
- nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp);
|
|
+ nv50_display_unk20_dp_hack(dev, dcb);
|
|
|
|
- if (dcbent->type != OUTPUT_ANALOG) {
|
|
+ if (dcb->type != OUTPUT_ANALOG) {
|
|
tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
|
|
tmp &= ~0x00000f0f;
|
|
if (script & 0x0100)
|
|
@@ -853,24 +881,61 @@ nv50_display_unk20_handler(struct drm_device *dev)
|
|
nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
|
|
}
|
|
|
|
+ dev_priv->evo_irq.dcb = dcb;
|
|
+ dev_priv->evo_irq.pclk = pclk;
|
|
+ dev_priv->evo_irq.script = script;
|
|
+
|
|
ack:
|
|
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20);
|
|
nv_wr32(dev, 0x610030, 0x80000000);
|
|
}
|
|
|
|
+/* If programming a TMDS output on a SOR that can also be configured for
|
|
+ * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
|
|
+ *
|
|
+ * It looks like the VBIOS TMDS scripts make an attempt at this, however,
|
|
+ * the VBIOS scripts on at least one board I have only switch it off on
|
|
+ * link 0, causing a blank display if the output has previously been
|
|
+ * programmed for DisplayPort.
|
|
+ */
|
|
+static void
|
|
+nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb)
|
|
+{
|
|
+ int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
|
|
+ struct drm_encoder *encoder;
|
|
+ u32 tmp;
|
|
+
|
|
+ if (dcb->type != OUTPUT_TMDS)
|
|
+ return;
|
|
+
|
|
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
|
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
|
+
|
|
+ if (nv_encoder->dcb->type == OUTPUT_DP &&
|
|
+ nv_encoder->dcb->or & (1 << or)) {
|
|
+ tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
|
|
+ tmp &= ~NV50_SOR_DP_CTRL_ENABLED;
|
|
+ nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
static void
|
|
nv50_display_unk40_handler(struct drm_device *dev)
|
|
{
|
|
- struct dcb_entry *dcbent;
|
|
- int head, pclk, script, ret;
|
|
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
+ struct dcb_entry *dcb = dev_priv->evo_irq.dcb;
|
|
+ u16 script = dev_priv->evo_irq.script;
|
|
+ u32 unk30 = nv_rd32(dev, 0x610030), pclk = dev_priv->evo_irq.pclk;
|
|
|
|
- ret = nv50_display_irq_head(dev, &head, &dcbent);
|
|
- if (ret)
|
|
+ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
|
|
+ dev_priv->evo_irq.dcb = NULL;
|
|
+ if (!dcb)
|
|
goto ack;
|
|
- pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
|
|
- script = nv50_display_script_select(dev, dcbent, pclk);
|
|
|
|
- nouveau_bios_run_display_table(dev, dcbent, script, -pclk);
|
|
+ nouveau_bios_run_display_table(dev, dcb, script, -pclk);
|
|
+ nv50_display_unk40_dp_set_tmds(dev, dcb);
|
|
|
|
ack:
|
|
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40);
|
|
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
|
|
index e20c0e2..fb0281a 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
|
|
@@ -28,41 +28,33 @@
|
|
#include "drm.h"
|
|
#include "nouveau_drv.h"
|
|
|
|
-struct nv50_fifo_priv {
|
|
- struct nouveau_gpuobj_ref *thingo[2];
|
|
- int cur_thingo;
|
|
-};
|
|
-
|
|
-#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
|
|
-
|
|
static void
|
|
-nv50_fifo_init_thingo(struct drm_device *dev)
|
|
+nv50_fifo_playlist_update(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv;
|
|
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
|
|
struct nouveau_gpuobj_ref *cur;
|
|
int i, nr;
|
|
|
|
NV_DEBUG(dev, "\n");
|
|
|
|
- cur = priv->thingo[priv->cur_thingo];
|
|
- priv->cur_thingo = !priv->cur_thingo;
|
|
+ cur = pfifo->playlist[pfifo->cur_playlist];
|
|
+ pfifo->cur_playlist = !pfifo->cur_playlist;
|
|
|
|
/* We never schedule channel 0 or 127 */
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
for (i = 1, nr = 0; i < 127; i++) {
|
|
if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc)
|
|
nv_wo32(dev, cur->gpuobj, nr++, i);
|
|
}
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
|
|
nv_wr32(dev, 0x32f4, cur->instance >> 12);
|
|
nv_wr32(dev, 0x32ec, nr);
|
|
nv_wr32(dev, 0x2500, 0x101);
|
|
}
|
|
|
|
-static int
|
|
-nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
|
|
+static void
|
|
+nv50_fifo_channel_enable(struct drm_device *dev, int channel)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_channel *chan = dev_priv->fifos[channel];
|
|
@@ -70,37 +62,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
|
|
|
|
NV_DEBUG(dev, "ch%d\n", channel);
|
|
|
|
- if (!chan->ramfc)
|
|
- return -EINVAL;
|
|
-
|
|
- if (IS_G80)
|
|
+ if (dev_priv->chipset == 0x50)
|
|
inst = chan->ramfc->instance >> 12;
|
|
else
|
|
inst = chan->ramfc->instance >> 8;
|
|
- nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel),
|
|
- inst | NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
|
|
|
|
- if (!nt)
|
|
- nv50_fifo_init_thingo(dev);
|
|
- return 0;
|
|
+ nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst |
|
|
+ NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
|
|
}
|
|
|
|
static void
|
|
-nv50_fifo_channel_disable(struct drm_device *dev, int channel, bool nt)
|
|
+nv50_fifo_channel_disable(struct drm_device *dev, int channel)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
uint32_t inst;
|
|
|
|
- NV_DEBUG(dev, "ch%d, nt=%d\n", channel, nt);
|
|
+ NV_DEBUG(dev, "ch%d\n", channel);
|
|
|
|
- if (IS_G80)
|
|
+ if (dev_priv->chipset == 0x50)
|
|
inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80;
|
|
else
|
|
inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84;
|
|
nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst);
|
|
-
|
|
- if (!nt)
|
|
- nv50_fifo_init_thingo(dev);
|
|
}
|
|
|
|
static void
|
|
@@ -133,12 +116,12 @@ nv50_fifo_init_context_table(struct drm_device *dev)
|
|
|
|
for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) {
|
|
if (dev_priv->fifos[i])
|
|
- nv50_fifo_channel_enable(dev, i, true);
|
|
+ nv50_fifo_channel_enable(dev, i);
|
|
else
|
|
- nv50_fifo_channel_disable(dev, i, true);
|
|
+ nv50_fifo_channel_disable(dev, i);
|
|
}
|
|
|
|
- nv50_fifo_init_thingo(dev);
|
|
+ nv50_fifo_playlist_update(dev);
|
|
}
|
|
|
|
static void
|
|
@@ -162,41 +145,38 @@ nv50_fifo_init_regs(struct drm_device *dev)
|
|
nv_wr32(dev, 0x3270, 0);
|
|
|
|
/* Enable dummy channels setup by nv50_instmem.c */
|
|
- nv50_fifo_channel_enable(dev, 0, true);
|
|
- nv50_fifo_channel_enable(dev, 127, true);
|
|
+ nv50_fifo_channel_enable(dev, 0);
|
|
+ nv50_fifo_channel_enable(dev, 127);
|
|
}
|
|
|
|
int
|
|
nv50_fifo_init(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- struct nv50_fifo_priv *priv;
|
|
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
|
|
int ret;
|
|
|
|
NV_DEBUG(dev, "\n");
|
|
|
|
- priv = dev_priv->engine.fifo.priv;
|
|
- if (priv) {
|
|
- priv->cur_thingo = !priv->cur_thingo;
|
|
+ if (pfifo->playlist[0]) {
|
|
+ pfifo->cur_playlist = !pfifo->cur_playlist;
|
|
goto just_reset;
|
|
}
|
|
|
|
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
- if (!priv)
|
|
- return -ENOMEM;
|
|
- dev_priv->engine.fifo.priv = priv;
|
|
-
|
|
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
|
|
- NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[0]);
|
|
+ NVOBJ_FLAG_ZERO_ALLOC,
|
|
+ &pfifo->playlist[0]);
|
|
if (ret) {
|
|
- NV_ERROR(dev, "error creating thingo0: %d\n", ret);
|
|
+ NV_ERROR(dev, "error creating playlist 0: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
|
|
- NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[1]);
|
|
+ NVOBJ_FLAG_ZERO_ALLOC,
|
|
+ &pfifo->playlist[1]);
|
|
if (ret) {
|
|
- NV_ERROR(dev, "error creating thingo1: %d\n", ret);
|
|
+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
|
|
+ NV_ERROR(dev, "error creating playlist 1: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
@@ -216,18 +196,15 @@ void
|
|
nv50_fifo_takedown(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv;
|
|
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
|
|
|
|
NV_DEBUG(dev, "\n");
|
|
|
|
- if (!priv)
|
|
+ if (!pfifo->playlist[0])
|
|
return;
|
|
|
|
- nouveau_gpuobj_ref_del(dev, &priv->thingo[0]);
|
|
- nouveau_gpuobj_ref_del(dev, &priv->thingo[1]);
|
|
-
|
|
- dev_priv->engine.fifo.priv = NULL;
|
|
- kfree(priv);
|
|
+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
|
|
+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]);
|
|
}
|
|
|
|
int
|
|
@@ -248,7 +225,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
|
|
|
|
NV_DEBUG(dev, "ch%d\n", chan->id);
|
|
|
|
- if (IS_G80) {
|
|
+ if (dev_priv->chipset == 0x50) {
|
|
uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start;
|
|
uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start;
|
|
|
|
@@ -281,10 +258,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
|
|
|
|
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
-
|
|
nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
|
|
- nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4));
|
|
+ nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ |
|
|
+ (4 << 24) /* SEARCH_FULL */ |
|
|
+ (chan->ramht->instance >> 4));
|
|
nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
|
|
nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
|
|
nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
|
|
@@ -295,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
|
|
chan->dma.ib_base * 4);
|
|
nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
|
|
|
|
- if (!IS_G80) {
|
|
+ if (dev_priv->chipset != 0x50) {
|
|
nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);
|
|
nv_wo32(dev, chan->ramin->gpuobj, 1,
|
|
chan->ramfc->instance >> 8);
|
|
@@ -304,16 +281,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
|
|
nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12);
|
|
}
|
|
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
-
|
|
- ret = nv50_fifo_channel_enable(dev, chan->id, false);
|
|
- if (ret) {
|
|
- NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret);
|
|
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
|
- nouveau_gpuobj_ref_del(dev, &chan->ramfc);
|
|
- return ret;
|
|
- }
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
|
|
+ nv50_fifo_channel_enable(dev, chan->id);
|
|
+ nv50_fifo_playlist_update(dev);
|
|
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
|
return 0;
|
|
}
|
|
@@ -328,11 +299,12 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
|
|
|
|
/* This will ensure the channel is seen as disabled. */
|
|
chan->ramfc = NULL;
|
|
- nv50_fifo_channel_disable(dev, chan->id, false);
|
|
+ nv50_fifo_channel_disable(dev, chan->id);
|
|
|
|
/* Dummy channel, also used on ch 127 */
|
|
if (chan->id == 0)
|
|
- nv50_fifo_channel_disable(dev, 127, false);
|
|
+ nv50_fifo_channel_disable(dev, 127);
|
|
+ nv50_fifo_playlist_update(dev);
|
|
|
|
nouveau_gpuobj_ref_del(dev, &ramfc);
|
|
nouveau_gpuobj_ref_del(dev, &chan->cache);
|
|
@@ -349,8 +321,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
|
|
|
|
NV_DEBUG(dev, "ch%d\n", chan->id);
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, false);
|
|
-
|
|
nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4));
|
|
nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4));
|
|
nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4));
|
|
@@ -396,7 +366,7 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
|
|
|
|
/* guessing that all the 0x34xx regs aren't on NV50 */
|
|
- if (!IS_G80) {
|
|
+ if (dev_priv->chipset != 0x50) {
|
|
nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4));
|
|
nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4));
|
|
nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4));
|
|
@@ -404,8 +374,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
|
|
nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4));
|
|
}
|
|
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
-
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16));
|
|
return 0;
|
|
}
|
|
@@ -434,8 +402,6 @@ nv50_fifo_unload_context(struct drm_device *dev)
|
|
ramfc = chan->ramfc->gpuobj;
|
|
cache = chan->cache->gpuobj;
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
-
|
|
nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330));
|
|
nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334));
|
|
nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240));
|
|
@@ -482,7 +448,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
|
|
}
|
|
|
|
/* guessing that all the 0x34xx regs aren't on NV50 */
|
|
- if (!IS_G80) {
|
|
+ if (dev_priv->chipset != 0x50) {
|
|
nv_wo32(dev, ramfc, 0x84/4, ptr >> 1);
|
|
nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c));
|
|
nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400));
|
|
@@ -491,7 +457,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
|
|
nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410));
|
|
}
|
|
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
|
|
/*XXX: probably reload ch127 (NULL) state back too */
|
|
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, 127);
|
|
diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c
|
|
index bb47ad7..88715c5 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv50_gpio.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv50_gpio.c
|
|
@@ -74,3 +74,22 @@ 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);
|
|
+}
|
|
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
|
|
index b203d06..1413028 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
|
|
@@ -30,8 +30,6 @@
|
|
|
|
#include "nouveau_grctx.h"
|
|
|
|
-#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
|
|
-
|
|
static void
|
|
nv50_graph_init_reset(struct drm_device *dev)
|
|
{
|
|
@@ -103,37 +101,33 @@ static int
|
|
nv50_graph_init_ctxctl(struct drm_device *dev)
|
|
{
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
+ struct nouveau_grctx ctx = {};
|
|
+ uint32_t *cp;
|
|
+ int i;
|
|
|
|
NV_DEBUG(dev, "\n");
|
|
|
|
- if (nouveau_ctxfw) {
|
|
- nouveau_grctx_prog_load(dev);
|
|
- dev_priv->engine.graph.grctx_size = 0x70000;
|
|
+ cp = kmalloc(512 * 4, GFP_KERNEL);
|
|
+ if (!cp) {
|
|
+ NV_ERROR(dev, "failed to allocate ctxprog\n");
|
|
+ dev_priv->engine.graph.accel_blocked = true;
|
|
+ return 0;
|
|
}
|
|
- if (!dev_priv->engine.graph.ctxprog) {
|
|
- struct nouveau_grctx ctx = {};
|
|
- uint32_t *cp = kmalloc(512 * 4, GFP_KERNEL);
|
|
- int i;
|
|
- if (!cp) {
|
|
- NV_ERROR(dev, "Couldn't alloc ctxprog! Disabling acceleration.\n");
|
|
- dev_priv->engine.graph.accel_blocked = true;
|
|
- return 0;
|
|
- }
|
|
- ctx.dev = dev;
|
|
- ctx.mode = NOUVEAU_GRCTX_PROG;
|
|
- ctx.data = cp;
|
|
- ctx.ctxprog_max = 512;
|
|
- if (!nv50_grctx_init(&ctx)) {
|
|
- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
|
|
-
|
|
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
|
|
- for (i = 0; i < ctx.ctxprog_len; i++)
|
|
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
|
|
- } else {
|
|
- dev_priv->engine.graph.accel_blocked = true;
|
|
- }
|
|
- kfree(cp);
|
|
+
|
|
+ ctx.dev = dev;
|
|
+ ctx.mode = NOUVEAU_GRCTX_PROG;
|
|
+ ctx.data = cp;
|
|
+ ctx.ctxprog_max = 512;
|
|
+ if (!nv50_grctx_init(&ctx)) {
|
|
+ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
|
|
+
|
|
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
|
|
+ for (i = 0; i < ctx.ctxprog_len; i++)
|
|
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
|
|
+ } else {
|
|
+ dev_priv->engine.graph.accel_blocked = true;
|
|
}
|
|
+ kfree(cp);
|
|
|
|
nv_wr32(dev, 0x400320, 4);
|
|
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
|
|
@@ -164,7 +158,6 @@ void
|
|
nv50_graph_takedown(struct drm_device *dev)
|
|
{
|
|
NV_DEBUG(dev, "\n");
|
|
- nouveau_grctx_fini(dev);
|
|
}
|
|
|
|
void
|
|
@@ -212,8 +205,9 @@ nv50_graph_create_context(struct nouveau_channel *chan)
|
|
struct drm_device *dev = chan->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
|
|
- struct nouveau_gpuobj *ctx;
|
|
+ struct nouveau_gpuobj *obj;
|
|
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
|
|
+ struct nouveau_grctx ctx = {};
|
|
int hdr, ret;
|
|
|
|
NV_DEBUG(dev, "ch%d\n", chan->id);
|
|
@@ -223,10 +217,9 @@ nv50_graph_create_context(struct nouveau_channel *chan)
|
|
NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
|
|
if (ret)
|
|
return ret;
|
|
- ctx = chan->ramin_grctx->gpuobj;
|
|
+ obj = chan->ramin_grctx->gpuobj;
|
|
|
|
- hdr = IS_G80 ? 0x200 : 0x20;
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
+ hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
|
|
nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
|
|
nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
|
|
pgraph->grctx_size - 1);
|
|
@@ -234,21 +227,15 @@ nv50_graph_create_context(struct nouveau_channel *chan)
|
|
nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
|
|
nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
|
|
nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
-
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
- if (!pgraph->ctxprog) {
|
|
- struct nouveau_grctx ctx = {};
|
|
- ctx.dev = chan->dev;
|
|
- ctx.mode = NOUVEAU_GRCTX_VALS;
|
|
- ctx.data = chan->ramin_grctx->gpuobj;
|
|
- nv50_grctx_init(&ctx);
|
|
- } else {
|
|
- nouveau_grctx_vals_load(dev, ctx);
|
|
- }
|
|
- nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
|
|
+ ctx.dev = chan->dev;
|
|
+ ctx.mode = NOUVEAU_GRCTX_VALS;
|
|
+ ctx.data = obj;
|
|
+ nv50_grctx_init(&ctx);
|
|
+
|
|
+ nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12);
|
|
+
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
return 0;
|
|
}
|
|
|
|
@@ -257,17 +244,16 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
|
|
{
|
|
struct drm_device *dev = chan->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- int i, hdr = IS_G80 ? 0x200 : 0x20;
|
|
+ int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
|
|
|
|
NV_DEBUG(dev, "ch%d\n", chan->id);
|
|
|
|
if (!chan->ramin || !chan->ramin->gpuobj)
|
|
return;
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
for (i = hdr; i < hdr + 24; i += 4)
|
|
nv_wo32(dev, chan->ramin->gpuobj, i/4, 0);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
|
|
nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
|
|
}
|
|
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
|
|
index 5f21df3..0c8a6f2 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
|
|
@@ -35,8 +35,6 @@ struct nv50_instmem_priv {
|
|
struct nouveau_gpuobj_ref *pramin_pt;
|
|
struct nouveau_gpuobj_ref *pramin_bar;
|
|
struct nouveau_gpuobj_ref *fb_bar;
|
|
-
|
|
- bool last_access_wr;
|
|
};
|
|
|
|
#define NV50_INSTMEM_PAGE_SHIFT 12
|
|
@@ -147,7 +145,7 @@ nv50_instmem_init(struct drm_device *dev)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base))
|
|
+ if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base))
|
|
return -ENOMEM;
|
|
|
|
/* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
|
|
@@ -262,23 +260,18 @@ nv50_instmem_init(struct drm_device *dev)
|
|
|
|
/* Assume that praying isn't enough, check that we can re-read the
|
|
* entire fake channel back from the PRAMIN BAR */
|
|
- dev_priv->engine.instmem.prepare_access(dev, false);
|
|
for (i = 0; i < c_size; i += 4) {
|
|
if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) {
|
|
NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n",
|
|
i);
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
|
|
nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
|
|
|
|
/* Global PRAMIN heap */
|
|
- if (nouveau_mem_init_heap(&dev_priv->ramin_heap,
|
|
- c_size, dev_priv->ramin_size - c_size)) {
|
|
- dev_priv->ramin_heap = NULL;
|
|
+ if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) {
|
|
NV_ERROR(dev, "Failed to init RAMIN heap\n");
|
|
}
|
|
|
|
@@ -321,7 +314,7 @@ nv50_instmem_takedown(struct drm_device *dev)
|
|
nouveau_gpuobj_del(dev, &chan->vm_pd);
|
|
nouveau_gpuobj_ref_del(dev, &chan->ramfc);
|
|
nouveau_gpuobj_ref_del(dev, &chan->ramin);
|
|
- nouveau_mem_takedown(&chan->ramin_heap);
|
|
+ drm_mm_takedown(&chan->ramin_heap);
|
|
|
|
dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
|
|
kfree(chan);
|
|
@@ -436,14 +429,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
|
|
if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
|
|
return -EINVAL;
|
|
|
|
- NV_DEBUG(dev, "st=0x%0llx sz=0x%0llx\n",
|
|
+ NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
|
|
gpuobj->im_pramin->start, gpuobj->im_pramin->size);
|
|
|
|
pte = (gpuobj->im_pramin->start >> 12) << 1;
|
|
pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
|
|
vram = gpuobj->im_backing_start;
|
|
|
|
- NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n",
|
|
+ NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
|
|
gpuobj->im_pramin->start, pte, pte_end);
|
|
NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
|
|
|
|
@@ -453,27 +446,15 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
|
|
vram |= 0x30;
|
|
}
|
|
|
|
- dev_priv->engine.instmem.prepare_access(dev, true);
|
|
while (pte < pte_end) {
|
|
nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
|
|
nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
|
|
vram += NV50_INSTMEM_PAGE_SIZE;
|
|
}
|
|
- dev_priv->engine.instmem.finish_access(dev);
|
|
-
|
|
- nv_wr32(dev, 0x100c80, 0x00040001);
|
|
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
|
|
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (1)\n");
|
|
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
|
|
- return -EBUSY;
|
|
- }
|
|
+ dev_priv->engine.instmem.flush(dev);
|
|
|
|
- nv_wr32(dev, 0x100c80, 0x00060001);
|
|
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
|
|
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
|
|
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
|
|
- return -EBUSY;
|
|
- }
|
|
+ nv50_vm_flush(dev, 4);
|
|
+ nv50_vm_flush(dev, 6);
|
|
|
|
gpuobj->im_bound = 1;
|
|
return 0;
|
|
@@ -492,36 +473,28 @@ 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, 0x070000, 0x00000001);
|
|
+ if (!nv_wait(0x070000, 0x00000001, 0x00000000))
|
|
+ NV_ERROR(dev, "PRAMIN flush timeout\n");
|
|
}
|
|
|
|
void
|
|
-nv50_instmem_finish_access(struct drm_device *dev)
|
|
+nv50_vm_flush(struct drm_device *dev, int engine)
|
|
{
|
|
- struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
|
|
-
|
|
- if (priv->last_access_wr) {
|
|
- nv_wr32(dev, 0x070000, 0x00000001);
|
|
- if (!nv_wait(0x070000, 0x00000001, 0x00000000))
|
|
- NV_ERROR(dev, "PRAMIN flush timeout\n");
|
|
- }
|
|
+ nv_wr32(dev, 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_mc.c b/drivers/gpu/drm/nouveau/nv50_mc.c
|
|
index e0a9c3f..f680e8e 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv50_mc.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv50_mc.c
|
|
@@ -31,7 +31,20 @@
|
|
int
|
|
nv50_mc_init(struct drm_device *dev)
|
|
{
|
|
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
+
|
|
nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF);
|
|
+
|
|
+ /* disable, and ack any pending gpio interrupts
|
|
+ * XXX doesn't technically belong here, but it'll do for the moment
|
|
+ */
|
|
+ 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_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
|
|
index 812778d..bcd4cf8 100644
|
|
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
|
|
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
|
|
@@ -37,52 +37,32 @@
|
|
#include "nv50_display.h"
|
|
|
|
static void
|
|
-nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
|
|
+nv50_sor_disconnect(struct drm_encoder *encoder)
|
|
{
|
|
- struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
|
|
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
|
+ struct drm_device *dev = encoder->dev;
|
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
|
struct nouveau_channel *evo = dev_priv->evo;
|
|
int ret;
|
|
|
|
+ if (!nv_encoder->crtc)
|
|
+ return;
|
|
+ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
|
|
+
|
|
NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
|
|
|
|
- ret = RING_SPACE(evo, 2);
|
|
+ ret = RING_SPACE(evo, 4);
|
|
if (ret) {
|
|
NV_ERROR(dev, "no space while disconnecting SOR\n");
|
|
return;
|
|
}
|
|
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
|
|
- OUT_RING(evo, 0);
|
|
-}
|
|
-
|
|
-static void
|
|
-nv50_sor_dp_link_train(struct drm_encoder *encoder)
|
|
-{
|
|
- struct drm_device *dev = encoder->dev;
|
|
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
|
- struct bit_displayport_encoder_table *dpe;
|
|
- int dpe_headerlen;
|
|
-
|
|
- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
|
|
- if (!dpe) {
|
|
- NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or);
|
|
- return;
|
|
- }
|
|
+ OUT_RING (evo, 0);
|
|
+ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
|
|
+ OUT_RING (evo, 0);
|
|
|
|
- if (dpe->script0) {
|
|
- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
|
|
- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
|
|
- nv_encoder->dcb);
|
|
- }
|
|
-
|
|
- if (!nouveau_dp_link_train(encoder))
|
|
- NV_ERROR(dev, "SOR-%d: link training failed\n", nv_encoder->or);
|
|
-
|
|
- if (dpe->script1) {
|
|
- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
|
|
- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
|
|
- nv_encoder->dcb);
|
|
- }
|
|
+ nv_encoder->crtc = NULL;
|
|
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
|
|
}
|
|
|
|
static void
|
|
@@ -94,14 +74,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
|
|
uint32_t val;
|
|
int or = nv_encoder->or;
|
|
|
|
- NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
|
|
+ NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode);
|
|
|
|
nv_encoder->last_dpms = mode;
|
|
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
|
|
struct nouveau_encoder *nvenc = nouveau_encoder(enc);
|
|
|
|
if (nvenc == nv_encoder ||
|
|
- nvenc->disconnect != nv50_sor_disconnect ||
|
|
+ (nvenc->dcb->type != OUTPUT_TMDS &&
|
|
+ nvenc->dcb->type != OUTPUT_LVDS &&
|
|
+ nvenc->dcb->type != OUTPUT_DP) ||
|
|
nvenc->dcb->or != nv_encoder->dcb->or)
|
|
continue;
|
|
|
|
@@ -133,8 +115,22 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
|
|
nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or)));
|
|
}
|
|
|
|
- if (nv_encoder->dcb->type == OUTPUT_DP && mode == DRM_MODE_DPMS_ON)
|
|
- nv50_sor_dp_link_train(encoder);
|
|
+ if (nv_encoder->dcb->type == OUTPUT_DP) {
|
|
+ struct nouveau_i2c_chan *auxch;
|
|
+
|
|
+ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
|
|
+ if (!auxch)
|
|
+ return;
|
|
+
|
|
+ if (mode == DRM_MODE_DPMS_ON) {
|
|
+ u8 status = DP_SET_POWER_D0;
|
|
+ nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
|
|
+ nouveau_dp_link_train(encoder);
|
|
+ } else {
|
|
+ u8 status = DP_SET_POWER_D3;
|
|
+ nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
static void
|
|
@@ -196,7 +192,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
uint32_t mode_ctl = 0;
|
|
int ret;
|
|
|
|
- NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
|
|
+ NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n",
|
|
+ nv_encoder->or, nv_encoder->dcb->type, crtc->index);
|
|
|
|
nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
|
|
|
|
@@ -239,6 +236,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
}
|
|
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
|
|
OUT_RING(evo, mode_ctl);
|
|
+
|
|
+ nv_encoder->crtc = encoder->crtc;
|
|
+}
|
|
+
|
|
+static struct drm_crtc *
|
|
+nv50_sor_crtc_get(struct drm_encoder *encoder)
|
|
+{
|
|
+ return nouveau_encoder(encoder)->crtc;
|
|
}
|
|
|
|
static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
|
|
@@ -249,7 +254,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
|
|
.prepare = nv50_sor_prepare,
|
|
.commit = nv50_sor_commit,
|
|
.mode_set = nv50_sor_mode_set,
|
|
- .detect = NULL
|
|
+ .get_crtc = nv50_sor_crtc_get,
|
|
+ .detect = NULL,
|
|
+ .disable = nv50_sor_disconnect
|
|
};
|
|
|
|
static void
|
|
@@ -272,32 +279,22 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = {
|
|
};
|
|
|
|
int
|
|
-nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
+nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
|
|
{
|
|
struct nouveau_encoder *nv_encoder = NULL;
|
|
+ struct drm_device *dev = connector->dev;
|
|
struct drm_encoder *encoder;
|
|
- bool dum;
|
|
int type;
|
|
|
|
NV_DEBUG_KMS(dev, "\n");
|
|
|
|
switch (entry->type) {
|
|
case OUTPUT_TMDS:
|
|
- NV_INFO(dev, "Detected a TMDS output\n");
|
|
+ case OUTPUT_DP:
|
|
type = DRM_MODE_ENCODER_TMDS;
|
|
break;
|
|
case OUTPUT_LVDS:
|
|
- NV_INFO(dev, "Detected a LVDS output\n");
|
|
type = DRM_MODE_ENCODER_LVDS;
|
|
-
|
|
- if (nouveau_bios_parse_lvds_table(dev, 0, &dum, &dum)) {
|
|
- NV_ERROR(dev, "Failed parsing LVDS table\n");
|
|
- return -EINVAL;
|
|
- }
|
|
- break;
|
|
- case OUTPUT_DP:
|
|
- NV_INFO(dev, "Detected a DP output\n");
|
|
- type = DRM_MODE_ENCODER_TMDS;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
@@ -310,8 +307,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
|
|
nv_encoder->dcb = entry;
|
|
nv_encoder->or = ffs(entry->or) - 1;
|
|
-
|
|
- nv_encoder->disconnect = nv50_sor_disconnect;
|
|
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
|
|
|
|
drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type);
|
|
drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);
|
|
@@ -342,5 +338,6 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
|
|
nv_encoder->dp.mc_unknown = 5;
|
|
}
|
|
|
|
+ drm_mode_connector_attach_encoder(connector, encoder);
|
|
return 0;
|
|
}
|
|
--
|
|
1.7.2.1
|
|
|