Martin Peres
2011-Jul-01 00:34 UTC
[Nouveau] [PATCH] drm/nouveau: set ptimer to count in ns on all chipset at the exception of nv40
From: Martin Peres <martin.peres at ensi-bourges.fr> May cause problems with your laptop screen on nv17-nv40 even though it should be very unlickely. nv40 isn't impacted by the patch as we need further reverse engineering to support it. Signed-off-by: Martin Peres <martin.peres at ensi-bourges.fr> --- drivers/gpu/drm/nouveau/Makefile | 3 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 ++ drivers/gpu/drm/nouveau/nouveau_reg.h | 9 ++-- drivers/gpu/drm/nouveau/nouveau_state.c | 17 ++++-- drivers/gpu/drm/nouveau/nv04_pm.c | 6 ++ drivers/gpu/drm/nouveau/nv04_timer.c | 66 ++++++++++++++++++----- drivers/gpu/drm/nouveau/nv41_timer.c | 90 +++++++++++++++++++++++++++++++ 7 files changed, 170 insertions(+), 25 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nv41_timer.c diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index f65ade6..da45a66 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -32,7 +32,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv50_calc.o \ nv04_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \ nv50_vram.o nvc0_vram.o \ - nv50_vm.o nvc0_vm.o + nv50_vm.o nvc0_vm.o \ + nv41_timer.o nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 3bb9716..a2027f5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1250,6 +1250,10 @@ extern int nv04_timer_init(struct drm_device *); extern uint64_t nv04_timer_read(struct drm_device *); extern void nv04_timer_takedown(struct drm_device *); +/* nv41_timer.c */ +extern int nv41_timer_init(struct drm_device *); +extern void nv41_timer_takedown(struct drm_device *); + extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index f18cdfc..de5f265 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -164,10 +164,11 @@ #define NV04_PTIMER_INTR_0 0x00009100 #define NV04_PTIMER_INTR_EN_0 0x00009140 -#define NV04_PTIMER_NUMERATOR 0x00009200 -#define NV04_PTIMER_DENOMINATOR 0x00009210 -#define NV04_PTIMER_TIME_0 0x00009400 -#define NV04_PTIMER_TIME_1 0x00009410 +#define NV04_PTIMER_CLOCK_DIV 0x00009200 +#define NV04_PTIMER_CLOCK_MUL 0x00009210 +#define NV41_PTIMER_CLOCK_SOURCE 0x00009220 +#define NV04_PTIMER_TIME_LOW 0x00009400 +#define NV04_PTIMER_TIME_HIGH 0x00009410 #define NV04_PTIMER_ALARM_0 0x00009420 #define NV04_PGRAPH_DEBUG_0 0x00400080 diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index f12a7ae..67b281d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -256,9 +256,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv40_mc_init; engine->mc.takedown = nv40_mc_takedown; - engine->timer.init = nv04_timer_init; + if (dev_priv->chipset == 0x40) { + engine->timer.init = nv04_timer_init; + engine->timer.takedown = nv04_timer_takedown; + } else { + engine->timer.init = nv41_timer_init; + engine->timer.takedown = nv41_timer_takedown; + } engine->timer.read = nv04_timer_read; - engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv40_fb_init; engine->fb.takedown = nv40_fb_takedown; engine->fb.init_tile_region = nv30_fb_init_tile_region; @@ -314,9 +319,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.flush = nv84_instmem_flush; engine->mc.init = nv50_mc_init; engine->mc.takedown = nv50_mc_takedown; - engine->timer.init = nv04_timer_init; + engine->timer.init = nv41_timer_init; engine->timer.read = nv04_timer_read; - engine->timer.takedown = nv04_timer_takedown; + engine->timer.takedown = nv41_timer_takedown; engine->fb.init = nv50_fb_init; engine->fb.takedown = nv50_fb_takedown; engine->fifo.channels = 128; @@ -389,9 +394,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.flush = nv84_instmem_flush; engine->mc.init = nv50_mc_init; engine->mc.takedown = nv50_mc_takedown; - engine->timer.init = nv04_timer_init; + engine->timer.init = nv41_timer_init; engine->timer.read = nv04_timer_read; - engine->timer.takedown = nv04_timer_takedown; + engine->timer.takedown = nv41_timer_takedown; engine->fb.init = nvc0_fb_init; engine->fb.takedown = nvc0_fb_takedown; engine->fifo.channels = 128; diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c index eb1c70d..ba5eb58 100644 --- a/drivers/gpu/drm/nouveau/nv04_pm.c +++ b/drivers/gpu/drm/nouveau/nv04_pm.c @@ -85,6 +85,12 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state) nv_mask(dev, 0x1002c0, 0, 1 << 8); } + /* On nv04-40, PTIMER depends on NVPLL. + * If we changed it, PTIMER must be set up again. + */ + if (dev_priv->card_type < NV_40 && reg == NV_PRAMDAC_NVPLL_COEFF) + nv04_timer_init(dev); + kfree(state); } diff --git a/drivers/gpu/drm/nouveau/nv04_timer.c b/drivers/gpu/drm/nouveau/nv04_timer.c index 1d09ddd..43004ce 100644 --- a/drivers/gpu/drm/nouveau/nv04_timer.c +++ b/drivers/gpu/drm/nouveau/nv04_timer.c @@ -3,23 +3,61 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +static void +ptimer_ratio(u32 refclk, u32 *d, u32 *m) +{ + if (!m || !d) + return; + + /* aim for 31.25MHz, which gives us nanosecond timestamps */ + *m = refclk; + *d = 1000000 / 32; + + /* reduce the ratio to accepted values */ + while (((*m % 5) == 0) && ((*d % 5) == 0)) { + *m /= 5; + *d /= 5; + } + + while (((*m % 2) == 0) && ((*d % 2) == 0)) { + *m /= 2; + *d /= 2; + } + + while (*m > 0xffff || *d > 0xffff) { + *m >>= 1; + *d >>= 1; + } +} + int nv04_timer_init(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine *engine = &dev_priv->engine; + int core_clock, m, d; + 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); + if (dev_priv->card_type < NV_40 || engine->pm.clock_get) { + core_clock = engine->pm.clock_get(dev, PLL_CORE); + ptimer_ratio(core_clock, &m, &d); + + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, d); + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, m); + } else { + /* As we can't depend on core clock, let's fallback to the old + * behaviour until we can do better. + */ + if (!nv_rd32(dev, NV04_PTIMER_CLOCK_DIV) || + !nv_rd32(dev, NV04_PTIMER_CLOCK_MUL)) { + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x00000008); + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x00000003); + } + + NV_ERROR(dev, + "Failed to setup PTIMER, fallback to default values\n"); } return 0; @@ -35,12 +73,12 @@ nv04_timer_read(struct drm_device *dev) * 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 high2 = nv_rd32(dev, NV04_PTIMER_TIME_HIGH); uint32_t high1; do { high1 = high2; - low = nv_rd32(dev, NV04_PTIMER_TIME_0); - high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); + low = nv_rd32(dev, NV04_PTIMER_TIME_LOW); + high2 = nv_rd32(dev, NV04_PTIMER_TIME_HIGH); } while (high1 != high2); return (((uint64_t)high2) << 32) | (uint64_t)low; } diff --git a/drivers/gpu/drm/nouveau/nv41_timer.c b/drivers/gpu/drm/nouveau/nv41_timer.c new file mode 100644 index 0000000..2233600 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv41_timer.c @@ -0,0 +1,90 @@ +/* + * Copyright 2011 Martin Peres + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" +#include "nouveau_drm.h" + +int +nv41_timer_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned int crystal; + + nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000); + nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF); + + crystal = (nv_rd32(dev, 0x101000) & 0x40) >> 6; + + if ((dev_priv->chipset >= 0x17 && dev_priv->chipset < 0x20) || + dev_priv->chipset > 0x25) { + crystal += (nv_rd32(dev, 0x101000) & 0x400000) >> 21; + } + + /* Set PTIMER to count in ns. + * As the last 5 bits are always 0, we only need to set PTIMER's + * frequency to 1/32 GHz = 31.25 MHz. + */ + switch (crystal) { + case 0: + /* Crystal frequency is 13500000 Hz + * 31.25 = 13.5 * 4 * 0xfa/0x288 + */ + nv_wr32(dev, NV41_PTIMER_CLOCK_SOURCE, 0x00000003); + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x000000288); + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x000000fa); + break; + case 1: + /* Crystal frequency is 14318800 Hz + * 31.25 = 14.3188 * 4 * 4c4b/8db5 + */ + nv_wr32(dev, NV41_PTIMER_CLOCK_SOURCE, 0x00000003); + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x00008db5); + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x00004c4b); + break; + case 2: + /* Crystal frequency is 27000000 Hz + * 31.25 = 27 * 3 * 0xfa/0x288 + */ + nv_wr32(dev, NV41_PTIMER_CLOCK_SOURCE, 0x00000002); + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x00000288); + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x000000fa); + break; + case 3: + /* Crystal frequency is 25000000 Hz + * 31.25 = 25 * 2 * 5 / 8 + */ + nv_wr32(dev, NV41_PTIMER_CLOCK_SOURCE, 0x00000001); + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x00000008); + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x00000005); + break; + } + + return 0; +} + +void +nv41_timer_takedown(struct drm_device *dev) +{ +} -- 1.7.6
Ben Skeggs
2011-Jul-04 06:42 UTC
[Nouveau] [PATCH] drm/nouveau: set ptimer to count in ns on all chipset at the exception of nv40
Apologies for top-posting. Martin, As per our convo on irc earlier, pushed code achieving this functionality. Let me know if there's issues :) Ben. Sent from my iPhone On 01/07/2011, at 10:34, Martin Peres <martin.peres at free.fr> wrote:> From: Martin Peres <martin.peres at ensi-bourges.fr> > > May cause problems with your laptop screen on nv17-nv40 even though it should > be very unlickely. > > nv40 isn't impacted by the patch as we need further reverse engineering to > support it. > > Signed-off-by: Martin Peres <martin.peres at ensi-bourges.fr> > --- > drivers/gpu/drm/nouveau/Makefile | 3 +- > drivers/gpu/drm/nouveau/nouveau_drv.h | 4 ++ > drivers/gpu/drm/nouveau/nouveau_reg.h | 9 ++-- > drivers/gpu/drm/nouveau/nouveau_state.c | 17 ++++-- > drivers/gpu/drm/nouveau/nv04_pm.c | 6 ++ > drivers/gpu/drm/nouveau/nv04_timer.c | 66 ++++++++++++++++++----- > drivers/gpu/drm/nouveau/nv41_timer.c | 90 +++++++++++++++++++++++++++++++ > 7 files changed, 170 insertions(+), 25 deletions(-) > create mode 100644 drivers/gpu/drm/nouveau/nv41_timer.c > > diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile > index f65ade6..da45a66 100644 > --- a/drivers/gpu/drm/nouveau/Makefile > +++ b/drivers/gpu/drm/nouveau/Makefile > @@ -32,7 +32,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ > nv50_calc.o \ > nv04_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \ > nv50_vram.o nvc0_vram.o \ > - nv50_vm.o nvc0_vm.o > + nv50_vm.o nvc0_vm.o \ > + nv41_timer.o > > nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o > nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o > diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h > index 3bb9716..a2027f5 100644 > --- a/drivers/gpu/drm/nouveau/nouveau_drv.h > +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h > @@ -1250,6 +1250,10 @@ extern int nv04_timer_init(struct drm_device *); > extern uint64_t nv04_timer_read(struct drm_device *); > extern void nv04_timer_takedown(struct drm_device *); > > +/* nv41_timer.c */ > +extern int nv41_timer_init(struct drm_device *); > +extern void nv41_timer_takedown(struct drm_device *); > + > extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, > unsigned long arg); > > diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h > index f18cdfc..de5f265 100644 > --- a/drivers/gpu/drm/nouveau/nouveau_reg.h > +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h > @@ -164,10 +164,11 @@ > > #define NV04_PTIMER_INTR_0 0x00009100 > #define NV04_PTIMER_INTR_EN_0 0x00009140 > -#define NV04_PTIMER_NUMERATOR 0x00009200 > -#define NV04_PTIMER_DENOMINATOR 0x00009210 > -#define NV04_PTIMER_TIME_0 0x00009400 > -#define NV04_PTIMER_TIME_1 0x00009410 > +#define NV04_PTIMER_CLOCK_DIV 0x00009200 > +#define NV04_PTIMER_CLOCK_MUL 0x00009210 > +#define NV41_PTIMER_CLOCK_SOURCE 0x00009220 > +#define NV04_PTIMER_TIME_LOW 0x00009400 > +#define NV04_PTIMER_TIME_HIGH 0x00009410 > #define NV04_PTIMER_ALARM_0 0x00009420 > > #define NV04_PGRAPH_DEBUG_0 0x00400080 > diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c > index f12a7ae..67b281d 100644 > --- a/drivers/gpu/drm/nouveau/nouveau_state.c > +++ b/drivers/gpu/drm/nouveau/nouveau_state.c > @@ -256,9 +256,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) > engine->instmem.flush = nv04_instmem_flush; > engine->mc.init = nv40_mc_init; > engine->mc.takedown = nv40_mc_takedown; > - engine->timer.init = nv04_timer_init; > + if (dev_priv->chipset == 0x40) { > + engine->timer.init = nv04_timer_init; > + engine->timer.takedown = nv04_timer_takedown; > + } else { > + engine->timer.init = nv41_timer_init; > + engine->timer.takedown = nv41_timer_takedown; > + } > engine->timer.read = nv04_timer_read; > - engine->timer.takedown = nv04_timer_takedown; > engine->fb.init = nv40_fb_init; > engine->fb.takedown = nv40_fb_takedown; > engine->fb.init_tile_region = nv30_fb_init_tile_region; > @@ -314,9 +319,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) > engine->instmem.flush = nv84_instmem_flush; > engine->mc.init = nv50_mc_init; > engine->mc.takedown = nv50_mc_takedown; > - engine->timer.init = nv04_timer_init; > + engine->timer.init = nv41_timer_init; > engine->timer.read = nv04_timer_read; > - engine->timer.takedown = nv04_timer_takedown; > + engine->timer.takedown = nv41_timer_takedown; > engine->fb.init = nv50_fb_init; > engine->fb.takedown = nv50_fb_takedown; > engine->fifo.channels = 128; > @@ -389,9 +394,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) > engine->instmem.flush = nv84_instmem_flush; > engine->mc.init = nv50_mc_init; > engine->mc.takedown = nv50_mc_takedown; > - engine->timer.init = nv04_timer_init; > + engine->timer.init = nv41_timer_init; > engine->timer.read = nv04_timer_read; > - engine->timer.takedown = nv04_timer_takedown; > + engine->timer.takedown = nv41_timer_takedown; > engine->fb.init = nvc0_fb_init; > engine->fb.takedown = nvc0_fb_takedown; > engine->fifo.channels = 128; > diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c > index eb1c70d..ba5eb58 100644 > --- a/drivers/gpu/drm/nouveau/nv04_pm.c > +++ b/drivers/gpu/drm/nouveau/nv04_pm.c > @@ -85,6 +85,12 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state) > nv_mask(dev, 0x1002c0, 0, 1 << 8); > } > > + /* On nv04-40, PTIMER depends on NVPLL. > + * If we changed it, PTIMER must be set up again. > + */ > + if (dev_priv->card_type < NV_40 && reg == NV_PRAMDAC_NVPLL_COEFF) > + nv04_timer_init(dev); > + > kfree(state); > } > > diff --git a/drivers/gpu/drm/nouveau/nv04_timer.c b/drivers/gpu/drm/nouveau/nv04_timer.c > index 1d09ddd..43004ce 100644 > --- a/drivers/gpu/drm/nouveau/nv04_timer.c > +++ b/drivers/gpu/drm/nouveau/nv04_timer.c > @@ -3,23 +3,61 @@ > #include "nouveau_drv.h" > #include "nouveau_drm.h" > > +static void > +ptimer_ratio(u32 refclk, u32 *d, u32 *m) > +{ > + if (!m || !d) > + return; > + > + /* aim for 31.25MHz, which gives us nanosecond timestamps */ > + *m = refclk; > + *d = 1000000 / 32; > + > + /* reduce the ratio to accepted values */ > + while (((*m % 5) == 0) && ((*d % 5) == 0)) { > + *m /= 5; > + *d /= 5; > + } > + > + while (((*m % 2) == 0) && ((*d % 2) == 0)) { > + *m /= 2; > + *d /= 2; > + } > + > + while (*m > 0xffff || *d > 0xffff) { > + *m >>= 1; > + *d >>= 1; > + } > +} > + > int > nv04_timer_init(struct drm_device *dev) > { > + struct drm_nouveau_private *dev_priv = dev->dev_private; > + struct nouveau_engine *engine = &dev_priv->engine; > + int core_clock, m, d; > + > 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); > + if (dev_priv->card_type < NV_40 || engine->pm.clock_get) { > + core_clock = engine->pm.clock_get(dev, PLL_CORE); > + ptimer_ratio(core_clock, &m, &d); > + > + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, d); > + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, m); > + } else { > + /* As we can't depend on core clock, let's fallback to the old > + * behaviour until we can do better. > + */ > + if (!nv_rd32(dev, NV04_PTIMER_CLOCK_DIV) || > + !nv_rd32(dev, NV04_PTIMER_CLOCK_MUL)) { > + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x00000008); > + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x00000003); > + } > + > + NV_ERROR(dev, > + "Failed to setup PTIMER, fallback to default values\n"); > } > > return 0; > @@ -35,12 +73,12 @@ nv04_timer_read(struct drm_device *dev) > * 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 high2 = nv_rd32(dev, NV04_PTIMER_TIME_HIGH); > uint32_t high1; > do { > high1 = high2; > - low = nv_rd32(dev, NV04_PTIMER_TIME_0); > - high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); > + low = nv_rd32(dev, NV04_PTIMER_TIME_LOW); > + high2 = nv_rd32(dev, NV04_PTIMER_TIME_HIGH); > } while (high1 != high2); > return (((uint64_t)high2) << 32) | (uint64_t)low; > } > diff --git a/drivers/gpu/drm/nouveau/nv41_timer.c b/drivers/gpu/drm/nouveau/nv41_timer.c > new file mode 100644 > index 0000000..2233600 > --- /dev/null > +++ b/drivers/gpu/drm/nouveau/nv41_timer.c > @@ -0,0 +1,90 @@ > +/* > + * Copyright 2011 Martin Peres > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + */ > + > +#include "drmP.h" > +#include "drm.h" > +#include "nouveau_drv.h" > +#include "nouveau_drm.h" > + > +int > +nv41_timer_init(struct drm_device *dev) > +{ > + struct drm_nouveau_private *dev_priv = dev->dev_private; > + unsigned int crystal; > + > + nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000); > + nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF); > + > + crystal = (nv_rd32(dev, 0x101000) & 0x40) >> 6; > + > + if ((dev_priv->chipset >= 0x17 && dev_priv->chipset < 0x20) || > + dev_priv->chipset > 0x25) { > + crystal += (nv_rd32(dev, 0x101000) & 0x400000) >> 21; > + } > + > + /* Set PTIMER to count in ns. > + * As the last 5 bits are always 0, we only need to set PTIMER's > + * frequency to 1/32 GHz = 31.25 MHz. > + */ > + switch (crystal) { > + case 0: > + /* Crystal frequency is 13500000 Hz > + * 31.25 = 13.5 * 4 * 0xfa/0x288 > + */ > + nv_wr32(dev, NV41_PTIMER_CLOCK_SOURCE, 0x00000003); > + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x000000288); > + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x000000fa); > + break; > + case 1: > + /* Crystal frequency is 14318800 Hz > + * 31.25 = 14.3188 * 4 * 4c4b/8db5 > + */ > + nv_wr32(dev, NV41_PTIMER_CLOCK_SOURCE, 0x00000003); > + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x00008db5); > + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x00004c4b); > + break; > + case 2: > + /* Crystal frequency is 27000000 Hz > + * 31.25 = 27 * 3 * 0xfa/0x288 > + */ > + nv_wr32(dev, NV41_PTIMER_CLOCK_SOURCE, 0x00000002); > + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x00000288); > + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x000000fa); > + break; > + case 3: > + /* Crystal frequency is 25000000 Hz > + * 31.25 = 25 * 2 * 5 / 8 > + */ > + nv_wr32(dev, NV41_PTIMER_CLOCK_SOURCE, 0x00000001); > + nv_wr32(dev, NV04_PTIMER_CLOCK_DIV, 0x00000008); > + nv_wr32(dev, NV04_PTIMER_CLOCK_MUL, 0x00000005); > + break; > + } > + > + return 0; > +} > + > +void > +nv41_timer_takedown(struct drm_device *dev) > +{ > +} > -- > 1.7.6 > > _______________________________________________ > Nouveau mailing list > Nouveau at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/nouveau