PTIMER

From NvWiki
Jump to navigation Jump to search

PTIMER is a hardware subsystem that implements a 56-bit programmable interval timer with nanosecond-ish accuracy (it counts in nanoseconds, but cannot be nanosecond accurate due to the clock speed) and controllable speed. It is a foundational component of all Nvidia GPUs and, at least for late 1990s and early 2000s GPU designs, has not changed a huge amount (although some new registers have been added) since the NV1. It is required to, among other things, for the graphics hardware to perform activities that involve waiting a defined amount of time, for the drivers to know when to poll for GPU state changes and many more things. All registers of PTIMER are located within the main GPU MMIO area. In order to use the PTIMER correctly, the PTIMER_NUMERATOR and PTIMER_DENOMINATOR registers must be programmed to appropriate values. Then, the PTIMER_ALARM register must be set in order to set when the alarm is reset. Then, each clock cycle, the PTIMER_TIME_0 (bits 31 through 5) and PTIMER_TIME_1 (bits 28 through 0) will update based on the number of nanoseconds that have passed. This will occur at a rate set by the result of the calculation MCLK * PTIMER_NUMERATOR / PTIMER_DENOMINATOR (where MCLK is the GPU core clock on NV3, and memory clock on NV4 and later). When PTIMER_TIME_1[1] is equal to PTIMER_ALARM, the PTIMER_INTR_ALARM interrupt will be fired and PTIMER_TIME_1 will be reset to zero (most likely, PTIMER_TIME_0 is incremented at this time). Disabling this interrupt is possible, but extremely unwise: if you are running under nVIDIA's Resource Manager, the drivers will most likely immediately cease to work, since PFIFO cache errors will never be caught, some I2C communication and several other critical events will not happen. Interrupts for the PTIMER subsystem cannot be turned off by using PMC's PMC_INTERRUPT_ENABLE register, nor can PTIMER be turned off using the global subsystem status in PMC_ENABLE.

Registers

PTIMER_INTR (Interrupt Status)

  • MMIO offset: 0x9100
  • Available in: NV1+
  • Read/write

Displays the current interrupt state for the PTIMER subsystem.

  • Bit 0 - PTIMER_INTR_ALARM - If this bit is set, the PTIMER alarm fired. Clear it when the interrupt has been successfully handled.

If bit 0 of PTIMER_INTR_EN is not set, disregard the value of this register.

PTIMER_INTR_EN (Interrupt Enable)

  • MMIO offset: 0x9140
  • Available in: NV1+
  • Read/write

Allows enabling and disabling interrupts for the PTIMER subsystem. In this case, there is only one interrupt to enable.

  • Bit 0 - PTIMER_INTR_EN_0_ALARM. Determines if the alarm interrupt is enabled - if this bit is not set, it will not be fired, effectively making this subsystem rather useless.

PTIMER_NUMERATOR (Time Count Speed Numerator)

  • MMIO offset: 0x9200
  • Available in: NV1+
  • Read/write

Bits 15 through 0 of this register contain the numerator of the fractional speed that the PTIMER_TIME_1 register will increment.

PTIMER_DENOMINATOR (Time Count Speed Denominator)

  • MMIO offset: 0x9210
  • Available in: NV1+
  • Read/write

Bits 15 through 0 of this register contain the denominator of the fractional speed that the PTIMER_TIME_1 register will increment. Presumably it is a bad idea to set this to zero (although it seems the PTIMER_TIME_1 just doesn't count when you do)

PTIMER_TIME_0

  • MMIO offset: 0x9400
  • Available in: NV1+
  • Read/write
  • Bits 31 through 5 of this register contain the high 27 bits of the PTIMER count register. This increments whenever PTIMER_TIME_1 rolls over to zero due to overflow.

PTIMER_TIME_1

  • MMIO offset: 0x9410
  • Available in: NV1+
  • Read/write
  • Bits 28 through 0 of this register contain the low 29 bits of the PTIMER count register. This increments every clock cycle by an amount equivalent to the result of the computation MCLK * PTIMER_NUMERATOR / PTIMER_DENOMINATOR, where MCLK is the aforementioned core GPU clock.

PTIMER_ALARM

  • MMIO offset: 0x9420
  • Available in: NV1+
  • Read/write
  • Contain the value that PTIMER_TIME_1 needs to hold for the PTIMER_INTR_ALARM interrupt to be triggered. There is no way to trigger an interrupt based on the value of PTIMER_TIME_0

Notes

^ The value of PTIMER_TIME_0 is not taken into account for the purposes of triggering the alarm interrupt.