linux/drivers/gpu/drm/nouveau/nv04_timer.c
Ben Skeggs afb0c796d8 drm/nouveau/tmr: fix miscalculation of ratio on pre-nv4x chipsets
The clock_get() hook returns KHz, not Hz.

Also fixed to use crystal freq from dev_priv.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
2011-09-20 16:08:54 +10:00

84 lines
1.6 KiB
C

#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
int
nv04_timer_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 m, n, d;
nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000);
nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF);
/* aim for 31.25MHz, which gives us nanosecond timestamps */
d = 1000000 / 32;
/* determine base clock for timer source */
if (dev_priv->chipset < 0x40) {
n = dev_priv->engine.pm.clock_get(dev, PLL_CORE);
} else
if (dev_priv->chipset == 0x40) {
/*XXX: figure this out */
n = 0;
} else {
n = dev_priv->crystal;
m = 1;
while (n < (d * 2)) {
n += (n / m);
m++;
}
nv_wr32(dev, 0x009220, m - 1);
}
if (!n) {
NV_WARN(dev, "PTIMER: unknown input clock freq\n");
if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) ||
!nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) {
nv_wr32(dev, NV04_PTIMER_NUMERATOR, 1);
nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 1);
}
return 0;
}
/* reduce ratio to acceptable values */
while (((n % 5) == 0) && ((d % 5) == 0)) {
n /= 5;
d /= 5;
}
while (((n % 2) == 0) && ((d % 2) == 0)) {
n /= 2;
d /= 2;
}
while (n > 0xffff || d > 0xffff) {
n >>= 1;
d >>= 1;
}
nv_wr32(dev, NV04_PTIMER_NUMERATOR, n);
nv_wr32(dev, NV04_PTIMER_DENOMINATOR, d);
return 0;
}
u64
nv04_timer_read(struct drm_device *dev)
{
u32 hi, lo;
do {
hi = nv_rd32(dev, NV04_PTIMER_TIME_1);
lo = nv_rd32(dev, NV04_PTIMER_TIME_0);
} while (hi != nv_rd32(dev, NV04_PTIMER_TIME_1));
return ((u64)hi << 32 | lo);
}
void
nv04_timer_takedown(struct drm_device *dev)
{
}