diff options
| author | John Ogness <john.ogness@linutronix.de> | 2019-02-28 16:24:43 +0106 |
|---|---|---|
| committer | John Ogness <john.ogness@linutronix.de> | 2019-02-28 16:24:43 +0106 |
| commit | 67ab994696ddb43158af3a951fd420c2a6a243ad (patch) | |
| tree | 34786a54a8df1c9c0b88a587f4a0c78bd6c14b45 | |
| parent | 6b8e3545c3d46a72e0ebd0f0cc53841e26ceee25 (diff) | |
notes: uio.txt
This text document goes through examples of how to use the
uio_pdrv_genirq driver for UIO drivers. It covers the device tree
entries for various scenarios as well as userspace code using
libuio to access/map the devices.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
| -rw-r--r-- | schulung_tools/notes/uio.txt | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/schulung_tools/notes/uio.txt b/schulung_tools/notes/uio.txt new file mode 100644 index 0000000..65d0176 --- /dev/null +++ b/schulung_tools/notes/uio.txt @@ -0,0 +1,195 @@ +HOWTO-UIO <john.ogness@linutronix.de> + + +This document briefly describes how to use UIO to develop userspace drivers. + + +=============== + Kernel Config +=============== + +The following kernel configuration options must be enabled. + + CONFIG_UIO=y + CONFIG_UIO_PDRV_GENIRQ=y + + +================ + Boot Arguments +================ + +The following boot argument must be present. + + uio_pdrv_genirq.of_id=generic-uio + + +============= + Device Tree +============= + +Each device must be specified in the device tree. Each device can have a +single mapping or multiple mappings (up to 1048576). Each device can have +maximum 1 interrupt associated with it. + +IMPORTANT: All mapping addresses must be page-aligned and the mapping sizes + must be an exact multiple of pages. 0x400 and 0x1400 are + examples of INVALID mapping sizes. 0x1000 and 0x2000 are examples + of VALID mapping sizes. + +Here are some device tree entry examples. + + /* 1 mapping, no interrupt */ + fpga-timer@0x43c15000 { + compatible = "generic-uio"; + reg = <0x43c15000 0x1000>; + }; + + /* 1 mapping with interrupt */ + fpga-dma@0x40400000 { + compatible = "generic-uio"; + reg = <0x40400000 0x1000>; + interrupts = <0 33 1>; + interrupt-parent = <&intc>; + }; + + /* 2 mappings with interrupt */ + fpga-leddisplay@0x43c16000 { + compatible = "generic-uio"; + reg = <0x43c16000 0x1000 0x43c18000 0x1000>; + interrupts = <0 34 1>; + interrupt-parent = <&intc>; + }; + +Specifying multiple mappings for a single device should only be done +if a single device really provides multiple memory regions. Although +allowed, it is not recommended to consolidate multiple devices into +a single device with multiple mappings since this tends to be +confusing. + + +==================== + Userspace - libuio +==================== + +A userspace library is available to allow simple usage of UIO: libuio. + + git clone https://github.com/Linutronix/libuio.git + +libuio uses glib by default. However, if glib is not already available on +the embedded system, it is recommended to build libuio without this extra +dependency + + $ ./configure --host=arm-none-linux-gnueabi --without-glib + + +========================= + Userspace - application +========================= + +Below is a simple application demonstrating how to use libuio. The +application uses a device with 2 mappings. For the first mapping, +it makes use of the libuio access functions (uio_read/uio_write) +to quickly access registers. For the second mapping, it casts the +memory to a structure to allow access without any functions. It +does not matter which method is used. The application simply +illustrates both possibilities. + +The device also provides an interrupt. The application waits for +3 interrupts before finishing. + +IMPORTANT: It is the responsibility of the application to clear + the hardware interrupt after each interrupt, if the + hardware requires interrupt clearing. + +Using libuio, the application never needs to know specific +information about the device (such as irq number, memory +address, memory size). This information, which is specified +in the device tree, is read by libuio dynamically each +time the application is run. + +libuio provides many helper functions not shown here. By +inspecting libuio.h or looking at the libuio source code it +should be fairly easy to identify what the various functions +do. (For example, uio_get_fd() is helpful if it is desired +to use select/poll to wait for interrupts.) + + +#include <stdio.h> +#include <errno.h> +#include <libuio.h> + +/* structure for map1 */ +struct hwregs { + uint32_t version; + uint32_t ctrl; + uint32_t irq_status; + uint32_t oe; +}; + +int main(void) +{ + volatile struct hwregs *regs; + struct uio_info_t *dev; + uint32_t val; + int i; + + /* get handle to UIO device */ + dev = uio_find_by_uio_name("fpga-leddisplay"); + if (!dev) { + fprintf(stderr, "unable to find UIO device\n"); + return 1; + } + + /* open UIO device */ + if (uio_open(dev) != 0) { + fprintf(stderr, "unable to open UIO device\n"); + return 1; + } + + /* read 32-bit value at offset 0x40 of map0 using libuio */ + if (uio_read32(dev, 0, 0x40, &val) != 0) { + fprintf(stderr, "unable to read\n"); + return 1; + } + printf("map0: 0x40 = 0x%x\n", val); + + /* use a struct to access registers of map1 */ + regs = uio_get_mem_map(dev, 1); + printf("map1: version = 0x%x\n", regs->version); + + /* make sure irq line is enabled */ + uio_enable_irq(dev); + + /* process 3 interrupts */ + for (i = 0; i < 3; i++) { + + /* blocking wait for interrupt */ + if (uio_irqwait(dev) != 0) { + fprintf(stderr, "irq wait failed: %s\n", + strerror(errno)); + return 1; + } + + /* + * Linux disabled the interrupt line. The userspace application + * is responsible for acknowledging the interrupt in hardware + * registers if the hardware requires that. Otherwise the + * interrupt will fire again as soon as the interrupt line is + * re-enabled. + */ + + /* acknowledge/clear the interrupt */ + regs->irq_status = 0x80; + + /* handle interrupt */ + printf("irq detected!\n"); + + /* re-enable interrupt line */ + uio_enable_irq(dev); + } + + /* close UIO device */ + uio_close(dev); + + return 0; +} |
