At work, we use a DisplayPort IP from Xilinx. Xilinx does not provide any driver
for this. There is a [TX](https://www.xilinx.com/support/documentation/ip_documentation/v_dp_txss1/v2_0/pg299-v-dp-txss1.pdf)
and [RX](https://www.xilinx.com/support/documentation/ip_documentation/v_dp_rxss1/v2_0/pg300-v-dp-rxss1.pdf).
Baremetal code support is provided, however, we needed support for Linux.
Ignoring interrupts, it is easy to get this baremetal code to work on Linux.
Xilinx's baremetal code at it's core uses [Xil_Out32](https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/standalone/src/common/xil_io.h#L219) and [Xil_In32](https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/standalone/src/common/xil_io.h#L147)
function for writing and reading to registers. The implementations for
these can be replaced with mmap for accessing the registers. For DP TX side, we
do not need to handle interrupts and setting up the registers is enough. For RX,
however, we need interrupts to setup RX. For example, the link training for DP
is initiated once a Training Pattern 1 (TP1) interrupt is detected.
Linux being a monolithic kernel, there is clear separation between kernel and
user space. Interrupts can only be handled in kernel space. However, it was
easier to use the ported baremetal code in user space and so we also needed to
handle interrupts in user space. Generally, one writes a driver to do all this
but since we only needed the interrupt part to be handled in kernel space, this
is where UIO subsystem comes in.
Using the UIO subsystem, it is possible to handle the interrupts in kernel space
while the rest like reading or writing to the registers can be done in user space.
There is a [Userspace I/O Platform driver with generic IRQ handling code](https://elixir.bootlin.com/linux/latest/source/drivers/uio/uio_pdrv_genirq.c).
I will take the example of Xilinx DisplayPort RX here. After my colleague who
works on FPGA side generates the FPGA firmware along with device trees which
has entries as per the peripherals configured on FPGA side, DP RX peripheral
let's say is in the memory region 0x80004000 to 0x80006000. An interrupt will
also be assinged based on how the FPGA Programmable Logic (PL) connects to the
Processing System (PS). PL is the FPGA and PS is the ARM64 SoC.
The extended device tree entry looks like this. *reg* specifies the memory that
can be mmaped in user space and accessed while the *interrupts* will be used by
the kernel code.
```c
&SUBBLOCK_DP_BASE_v_dp_rxss1_0 {
compatible = "dprxss-uio";
interrupt-parent = <&gic>;
interrupts = <09240924>;
reg = <0x00x800040000x00x2000>
status = "okay";
}
```
To link the UIO platform driver to this, we add the following to the *bootargs*
environment variable in u-boot.
```c
uio_pdrv_genirq.of_id=dprxss-uio
```
We need to do this, since the compatible property for device tree is not specified
in the driver. See [here](https://elixir.bootlin.com/linux/latest/source/drivers/uio/uio_pdrv_genirq.c#L252).