nv04_timer.c 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. #include "drmP.h"
  2. #include "drm.h"
  3. #include "nouveau_drv.h"
  4. #include "nouveau_drm.h"
  5. int
  6. nv04_timer_init(struct drm_device *dev)
  7. {
  8. nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000);
  9. nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF);
  10. /* Just use the pre-existing values when possible for now; these regs
  11. * are not written in nv (driver writer missed a /4 on the address), and
  12. * writing 8 and 3 to the correct regs breaks the timings on the LVDS
  13. * hardware sequencing microcode.
  14. * A correct solution (involving calculations with the GPU PLL) can
  15. * be done when kernel modesetting lands
  16. */
  17. if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) ||
  18. !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) {
  19. nv_wr32(dev, NV04_PTIMER_NUMERATOR, 0x00000008);
  20. nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 0x00000003);
  21. }
  22. return 0;
  23. }
  24. uint64_t
  25. nv04_timer_read(struct drm_device *dev)
  26. {
  27. uint32_t low;
  28. /* From kmmio dumps on nv28 this looks like how the blob does this.
  29. * It reads the high dword twice, before and after.
  30. * The only explanation seems to be that the 64-bit timer counter
  31. * advances between high and low dword reads and may corrupt the
  32. * result. Not confirmed.
  33. */
  34. uint32_t high2 = nv_rd32(dev, NV04_PTIMER_TIME_1);
  35. uint32_t high1;
  36. do {
  37. high1 = high2;
  38. low = nv_rd32(dev, NV04_PTIMER_TIME_0);
  39. high2 = nv_rd32(dev, NV04_PTIMER_TIME_1);
  40. } while (high1 != high2);
  41. return (((uint64_t)high2) << 32) | (uint64_t)low;
  42. }
  43. void
  44. nv04_timer_takedown(struct drm_device *dev)
  45. {
  46. }