.. _peephole:

==========================================
PEEPHOLE: indirect memory access from host
==========================================

.. contents::


Introduction
============

PEEPHOLE is a mechanism to indirectly access memory form the CPU. It is
present on NV30+ cards. On NV30:G80, it accesses physical [unpaged] VRAM.
On G80+, it can access either physical VRAM, or virtual [paged] memory via
standard VM circuitry. Additionally, on G84+, the PEEPHOLE MMIO registers
are stuffed into a dedicated range [0x060000:0x061000], so that the driver
can allow userspace programs access to the PEEPHOLE and nothing else.

PEEPHOLE is part of PBUS and thus not affected by any PMC.ENABLE bit. The
actual memory access is handled by PFIFO on G80+ cards.

The PEEPHOLE has two ports: a write-only port and a read-write port. The ports
share a common VM context on G80+, but are otherwise independent. The
write-only port is only present on NV30:GF100.

The addresses used for PEEPHOLE accesses have to be 4-byte aligned, and the
window for indirect access is 4 bytes long. The addresses are 29-bit on
NV30:G80 [enough to address all of VRAM], 32-bit on G80:GF100, 40-bit on
GF100+.

For details on setting up the target physical/VM space on G80:GF100, see
:ref:`g80-host-mem`; for GF100+ see :ref:`gf100-host-mem`.

Note that, on NV30:GF100 cards, the PEEPHOLE is subject to PMC hidden window
masking - see :ref:`pmc-vram-hide` for details.


.. _peephole-mmio:

MMIO registers
==============

The following MMIO registers deal with PEEPHOLE:

======== ========== ===================== ====================
Address  Present on Name                  Description
======== ========== ===================== ====================
0x00155c NV30:GF100 PEEPHOLE_W_CTRL       :ref:`write port control <peephole-mmio-w>`
0x001560 NV30:G84   PEEPHOLE_W_ADDR       :ref:`write port address <peephole-mmio-w>`
0x001564 NV30:G84   PEEPHOLE_W_DATA       :ref:`write port data <peephole-mmio-w>`
0x001570 NV30:G84   PEEPHOLE_RW_ADDR      :ref:`read-write port address <peephole-mmio-rw>`
0x001574 NV30:G84   PEEPHOLE_RW_DATA      :ref:`read-write port data <peephole-mmio-rw>`
======== ========== ===================== ====================

.. space:: 8 peephole 0x1000 indirect VM access

   .. todo:: convert

   0x060000 G84:GF100  PEEPHOLE_W_ADDR       :ref:`write port address <peephole-mmio-w>`
   0x060004 G84:GF100  PEEPHOLE_W_DATA       :ref:`write port data <peephole-mmio-w>`
   0x06000c GF100-      PEEPHOLE_RW_ADDR_HIGH :ref:`read-write port address, high part <peephole-mmio-rw>`
   0x060010 G84-       PEEPHOLE_RW_ADDR_LOW  :ref:`read-write port address, low part <peephole-mmio-rw>`
   0x060014 G84-       PEEPHOLE_RW_DATA      :ref:`read-write port data <peephole-mmio-rw>`

In addition, PEEPHOLE uses PBUS interrupt #12 for its write port.


.. _pbus-intr-peephole-w-pair-mismatch:
.. _peephole-mmio-w:

Write port
==========

Write port is present on NV30:GF100 cards only. The write port consists of
an address register, a data register, and a control register. It can operate
in two modes:

- paired write mode: The address and data registers are supposed to be
  accessed by two back-to-back writes, in either order. The back-to-back
  write is supposed to be generated by software doing a 64-bit write on the
  address covering both of these registers. Writing these registers in any
  other way, or doing any other MMIO write between the writes, is an error
  and will cause an interrupt. The memory write will be performed on the
  second write of the pair.
- freeform mode: both registers can be accessed in any manner, any write
  to the data register will perform a memory write.

The mode of operation and current status can be read/written via the
PEEPHOLE_W_CTRL register:

MMIO 0x00155c: PEEPHOLE_W_CTRL [NV30:GF100]
  - bit 0: PAIR_ADDR_VALID - 1 when an address write has been performed, and the
    hw is waiting for a data write
  - bit 1: PAIR_DATA_VALID - 1 when a data write has been performed, and the hw
    is waiting for an address write
  - bit 8: MODE

    - 0: PAIR - selects paired write mode
    - 1: FREEFORM - selects freeform mode

The address and data registers are:

MMIO 0x001560: PEEPHOLE_W_ADDR [NV30:G84]

MMIO 0x060000: PEEPHOLE_W_ADDR [G84:GF100]
  The address register. On NV30:G80, only bits 2-28 are valid. On G80+, only
  bits 2-31 are valid.

MMIO 0x001564: PEEPHOLE_W_DATA [NV30:G84]

MMIO 0x060004: PEEPHOLE_W_DATA [G84:GF100]
  The data register. This register is actually RW, and a read will return the
  last written value. Writes other than 32-bit are accepted, but will translate
  to appropriately-sized memory writes *only if the memory write is triggered
  by the data register write* - if the memory write is triggered by address
  register write, a 32-bit memory write will be performed instead, with junk
  in the remaining bytes.

PEEPHOLE_W_ADDR write operation::

	PEEPHOLE_W_ADDR = value;
	if (MODE == PAIR) {
		if (PAIR_ADDR_VALID) {
			raise_irq(PBUS.INTR.PEEPHOLE_W_PAIR_MISMATCH);
		} else if (PAIR_DATA_VALID) {
			peephole_write32(PEEPHOLE_W_ADDR, PEEPHOLE_W_DATA);
			PAIR_DATA_VALID = 0;
		} else {
			PAIR_ADDR_VALID = 1;
		}
	}

PEEPHOLE_W_DATA write operation::

	PEEPHOLE_W_DATA = value;
	if (MODE == PAIR) {
		if (PAIR_DATA_VALID) {
			raise_irq(PBUS.INTR.PEEPHOLE_W_PAIR_MISMATCH);
		} else if (PAIR_ADDR_VALID) {
			peephole_write_be(PEEPHOLE_W_ADDR, value, value_be); /* memory write byte enables copied from the MMIO access */
			PAIR_ADDR_VALID = 0;
		} else {
			PAIR_DATA_VALID = 1;
		}
	} else {
		peephole_write_be(PEEPHOLE_W_ADDR, value, value_be); /* memory write byte enables copied from the MMIO access */
	}

The PEEPHOLE_W_PAIR_MISMATCH interrupt is reported in
:ref:`PBUS.INTR bit 12 <pbus-intr>`.


.. _peephole-mmio-rw:

RW port operation
=================

The RW port is available on all NV30+ cards. There is an address register and
a data register. Accesses to the address register merely read/write that
register. All accesses to the data register are translated to equivalent
memory accesses at the address selected by the address register, and cause
the address register to auto-increment by 4. The translation preserves byte
enables, thus it's possible to do accesses smaller than 32 bits [though the
address will always autoincrement by 4].

MMIO 0x06000c: PEEPHOLE_RW_ADDR_HIGH [GF100-]
  The high part of the address register - bits 0-7 are valid and correspond to
  address bits 32-39.

MMIO 0x001570: PEEPHOLE_RW_ADDR [NV30:G84]

MMIO 0x060010: PEEPHOLE_RW_ADDR_LOW [G84-]
  The low part of the address register. On NV30:G80, only bits 2-28 are
  valid. On G80+, only bits 2-31 are valid.

MMIO 0x001574: PEEPHOLE_RW_DATA [NV30:G84]

MMIO 0x060014: PEEPHOLE_RW_DATA [G84-]
  The data port. Any access to this address will be translated to
  a corresponding memory read/write and cause the address register to be
  autoincremented by 4. On GF100+, the carry from LOW to HIGH is handled
  properly.
