linux/drivers/gpu/drm/nouveau/nv04_timer.c
Ben Skeggs 6ee738610f drm/nouveau: Add DRM driver for NVIDIA GPUs
This adds a drm/kms staging non-API stable driver for GPUs from NVIDIA.

This driver is a KMS-based driver and requires a compatible nouveau
userspace libdrm and nouveau X.org driver.

This driver requires firmware files not available in this kernel tree,
interested parties can find them via the nouveau project git archive.

This driver is reverse engineered, and is in no way supported by nVidia.

Support for nearly the complete range of nvidia hw from nv04->g80 (nv50)
is available, and the kms driver should support driving nearly all
output types (displayport is under development still) along with supporting
suspend/resume.

This work is all from the upstream nouveau project found at
nouveau.freedesktop.org.

The original authors list from nouveau git tree is:
Anssi Hannula <anssi.hannula@iki.fi>
Ben Skeggs <bskeggs@redhat.com>
Francisco Jerez <currojerez@riseup.net>
Maarten Maathuis <madman2003@gmail.com>
Marcin Kościelnicki <koriakin@0x04.net>
Matthew Garrett <mjg@redhat.com>
Matt Parnell <mparnell@gmail.com>
Patrice Mandin <patmandin@gmail.com>
Pekka Paalanen <pq@iki.fi>
Xavier Chantry <shiningxc@gmail.com>
along with project founder Stephane Marchesin <marchesin@icps.u-strasbg.fr>

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2009-12-11 21:29:34 +10:00

52 lines
1.4 KiB
C

#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
int
nv04_timer_init(struct drm_device *dev)
{
nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000);
nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF);
/* Just use the pre-existing values when possible for now; these regs
* are not written in nv (driver writer missed a /4 on the address), and
* writing 8 and 3 to the correct regs breaks the timings on the LVDS
* hardware sequencing microcode.
* A correct solution (involving calculations with the GPU PLL) can
* be done when kernel modesetting lands
*/
if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) ||
!nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) {
nv_wr32(dev, NV04_PTIMER_NUMERATOR, 0x00000008);
nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 0x00000003);
}
return 0;
}
uint64_t
nv04_timer_read(struct drm_device *dev)
{
uint32_t low;
/* From kmmio dumps on nv28 this looks like how the blob does this.
* It reads the high dword twice, before and after.
* The only explanation seems to be that the 64-bit timer counter
* advances between high and low dword reads and may corrupt the
* result. Not confirmed.
*/
uint32_t high2 = nv_rd32(dev, NV04_PTIMER_TIME_1);
uint32_t high1;
do {
high1 = high2;
low = nv_rd32(dev, NV04_PTIMER_TIME_0);
high2 = nv_rd32(dev, NV04_PTIMER_TIME_1);
} while (high1 != high2);
return (((uint64_t)high2) << 32) | (uint64_t)low;
}
void
nv04_timer_takedown(struct drm_device *dev)
{
}