UIO device no longer opens when an interrupt is added - linux

Linux version: v4.19
Platform: Xilinx Ultrascale+ Zynq
In the Xilinx programmable logic I've created a memory mapped device. I'm using uio_pdrv_genirq as my device driver. The device shows up as uio0 and I'm able to read and write to it without any issues.
Up until now I have not had an interrupt associated with this device. As my design matures, I'm wanting to add an interrupt to the device. So I've created the appropriate logic, connected the interrupt to the CPU, and updated the device tree configuration to tell Linux about the interrupt's existence. I've checked thoroughly and I'm quite certain that I am specifying the correct interrupt ID in the device tree.
However as soon as I specify the interrupt, I start having problems. My user space program hangs when I try to open the device. I've verified with printf():s that I'm no longer exiting this function.
fid = open("/dev/uio0", O_RDWR | O_SYNC);
Clearly this has something to do with the interrupt. Perhaps there is some additional device tree configuration of the interrupt controller that I'm missing? Or something I have to do in user space before opening the device?
Here is the device tree configuration for my device and the interrupt controller:
my_device#a0040000 {
compatible = "generic-uio";
reg = <0x0 0xa0040000 0x0 0x40000>;
interrupt-parent = <&gic>;
interrupts = <0 89 4>;
};
gic: interrupt-controller#f9010000 {
compatible = "arm,gic-400", "arm,cortex-a15-gic";
#interrupt-cells = <3>;
reg = <0x0 0xf9010000 0x10000>,
<0x0 0xf9020000 0x20000>,
<0x0 0xf9040000 0x20000>,
<0x0 0xf9060000 0x20000>;
interrupt-controller;
interrupt-parent = <&gic>;
interrupts = <1 9 0xf04>;
};

Related

Why does the device tree have to list interrupts for a UART device?

On the device file tree listed here we can see an UART device:
uarta: serial#70006000 {
compatible = "nvidia,tegra210-uart", "nvidia,tegra20-uart";
reg = <0x0 0x70006000 0x0 0x40>;
reg-shift = <2>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_UARTA>;
clock-names = "serial";
resets = <&tegra_car 6>;
reset-names = "serial";
dmas = <&apbdma 8>, <&apbdma 8>;
dma-names = "rx", "tx";
status = "disabled";
};
The tegra210-uart driver is declared here
Why does uarta needs the interrupts section? Does it produce or receive interrupts? My guess is that it produces software interrupts: when it writes something to the serial, it triggers an interrupt. But why must this interrupt be listed in the device tree? And where is the code for this interrupt?
The second line of the above code block (reg = <0x0 0x70006000 0x0 0x40>) refers to an uart address. What is this address exactly? If I understand correctly, this is the address for a 8250_UART device but I'd like to know which pieces of this address do what, and how the kernel talks with this chip.
Driver documentation is available at https://www.kernel.org/doc/Documentation/devicetree/bindings/serial/nvidia%2Ctegra20-hsuart.txt
According to this forum https://forums.developer.nvidia.com/t/enabling-interrupts-for-uart-xavier-agx/166269
interrupts are used to prevent regular polling on UART.
Registering handler on this interrupt allows to only run code when effective data are received and available in DMA buffer, or when the complete outgoing message provided in DMA has been sent. Such a DMA usage example is available at: UART Tx mode with DMA enabled
Memory address 0x70006000 is the base location for UARTA controller registers (there are 4 UART [A,B,C,D] in Tegra 2) where to write commands or read status. These documents may help to understand:
https://docs.freebsd.org/en/articles/serial-uart/index.html
https://www.lammertbies.nl/comm/info/serial-uart
For instance, the Scratch Register (SCR +0x07) can be used to write and read back any byte as a way to test UART is present and controller operates as expected.
I recommend you to download reference documentation, chapter 22 for UART, available from https://developer.nvidia.com/embedded/tegra-2-reference

Handling pin modes from devicetree to module

I am trying to write a linux device driver for a SPI device, using Atmels SAMA5d35 MPU. Linux version is 4.19.30.
I have configured the pins in my device tree and set the status to "okay".
After that the pins changed mode as expected. My question is then, how do I manipulate pinmodes during runtime? My SPI device is not always on, neither is my driver always loaded. When that is the case I want the configured SPI pins to change mode to normal GPIOs (for power-consumption).
Is it the drivers task to do that, or is it something one can define in the device tree, when the driver for example is not loaded?
I have tried to implement a pinctrl-0 for setting the pins to SPI mode, and then a pinctrl-1 for setting the same pins to normal GPIOs. My idea was to switch between these pin configuration in the device driver, but unfortunately the device tree complaints about using the same pins for both pinctrl-0 and pinctrl-1 (compiles fine, but system wont boot). Although this was just my logical thoughts. I am sure there is a more correct way to do the things I stated above.
spi0: spi#f0004000 {
status = "okay";
ext_adc: ads1258#1 {
compatible = "ti,ads1258";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_spi0_default>;
pinctrl-1 = <&pinctrl_spi0_sleep>;
reg = <1>; /* Hardware chipselect SPI0_NPCS1 */
spi-max-frequency = <16000000>; /* According to datasheet */
start-gpios = <&pioD 5 GPIO_ACTIVE_HIGH>;
drdy-gpios = <&pioD 22 GPIO_ACTIVE_LOW>;
enaadc-gpios = <&pioA 26 GPIO_ACTIVE_HIGH>;
};
};
My question is then, how do I manipulate pinmodes during runtime?
That's called "Runtime pinmuxing", which is described in Documentation/pinctrl.txt.
But you may not have to do that.
When that is the case I want the configured SPI pins to change mode to normal GPIOs (for power-consumption).
Is it the drivers task to do that, or is it something one can define in the device tree, when the driver for example is not loaded?
The default mode for a pin (of Atmel/Microchip SoCs) is to be unassigned to any peripheral mode, and be available for use as a GPIO.
All pins that are not assigned to a peripheral or acquired by a driver as a GPIO, end up in the pool of available GPIOs.
So when your SPI driver is not successfully installed, those pins it would use will be in the pool of available GPIOs.
I have tried to implement a pinctrl-0 for setting the pins to SPI mode, and then a pinctrl-1 for setting the same pins to normal GPIOs.
Assigning pins for use by the SPI controller is proper, but there is no mechanism AFAIK for assigning a pin to be an available GPIO.
You can only define properties in the DT for what a device, such as the SPI controller, requires.
There is no mechanism for an "alternate" assignment.
I am sure there is a more correct way to do the things I stated above.
If your driver does not install, then its resources such as its pins should not be allocated. The pins that the SPI would have used will remain unused, and end up in the pool of available GPIOs (unless something else claims/requests one of those pins).
So your DT needs to simply define what your device uses, and leave it at that.
If you still want your driver to modify the state of its pin, then study the section titled "Pin control requests from drivers" in Documentation/pinctrl.txt.

Linux I2C kernel driver binding

I am learning about how to develop a Linux I2C kernel driver, and I learn from websites below.
How to instantiate I2C devices
I2C Driver for Linux Based Embedded System
...
Next, I found a sample that shows how to implement a I2C touchpad driver, but it really confused me.
linux/drivers/input/mouse/synaptics_i2c.c
My question is, how Linux kernel bind this driver to correctly device? This driver don't provide 'detect' callback, no specify the I2C slave address via i2c_driver.address_list, and there is seems no anyone to call i2c_board_info to register the address info (I grep a whole Linux codebase).
I thought the driver MUST be specify the slave address or provide the 'detect' callback, just like
drivers/hwmon/adc128d818.c
or
linux/drivers/rtc/rtc-ds1307.c (it will be register by i2c_board_info)
Please let me know what I missed, thanks.
The i2c device declaration is start from device tree.
Declare the i2c devices in device tree.
Example:
i2c1: i2c#400a0000 {
/* ... master properties skipped ... */
clock-frequency = <100000>;
flash#50 {
compatible = "atmel,24c256";
reg = <0x50>;
};
pca9532: gpio#60 {
compatible = "nxp,pca9532";
gpio-controller;
#gpio-cells = <2>;
reg = <0x60>;
};
};
Where,
1) 400a000 is a i2c bus address
2) pca9532 and flash are driver names
3) #50 and #60 are slave address
4) the attribute “compatible” to find and map device with the driver
5) other attribute which is inside cell of each entries are specific to the driver which will be used for device initialization during the probe
https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
I finally figured out my question.
Refer to http://www.embedded-bits.co.uk/2009/i2c-in-the-2632-linux-kernel/
There is need to register my I2C device with i2c_new_probed_device() or i2c_new_device on Kernel to let it have a mapping table about slave address and device name.

How does Linux kernel know what CPU peripheral registers it has?

I have spent some time on linux driver, and this question always confused me: how does kernel know where, and what, on-chip peripheral register the CPU it is running on has?
For example, I am using a Cyclone V SOC with an ARM A9 inside. It has 4 I2C controller, and the base address of each is 0xFFC04000, 0xFFC05000, 0xFFC06000, and 0xFFC07000. Upon each base address, there is an Control Register at offset 0x0, a Data Register at offset 0Xx10, and so on.
Whatever data structure I2C driver model has, all those operations from driver C code should finally be reflected to the operations to those registers, right? If you want to get your I2C RX data, finally there should be some operations fetching at the Data Register, which is the only place the data could be on whole CPU. How does kernel know what registers the CPU's peripheral has and where are them, and the functionality of each of them?
I know device tree provide some information to kernel on hardware resources, but typically it is like:
i2c0: i2c#ffc04000
{
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,designware-i2c";
reg = <0xffc04000 0x1000>;
interrupts = <0 158 4>;
clocks = <&l4_sp_clk>;
status = "okay";
};
It only tells CPU the base address of first I2C controller is at 0xffc04000, and the length of its register section is 0x1000. Nothing else. The CPU still doesn't know what is inside this 0x1000 section, what registers are there, what purpose, what address offset.
I know mmap/ioremap can map physical address to virtual address, but this is not what I am asking for.
Thanks so much~~

How to program Linux .dts device tree files?

I'm going to launch a Linux on my development board, and i need a dts file (device tree file) to describe the whole hardware. But I only know very little about the syntax of this file which is not enough to run Linux properly on the board.
What i know now are only how to describe a unit's interrupt number, frequency, address, parent-unit and its compatible driver type (as described below):
ps7_scuwdt_0: ps7-scuwdt#f8f00620 {
compatible = "xlnx,ps7-scuwdt-1.00.a";
device_type = "watchdog";
interrupt-parent = <&ps7_scugic_0>;
interrupts = < 1 14 769 >;
reg = < 0xf8f00620 0xe0 >;
} ;
Other advanced usage or grammar is unfamiliar to me.
Take a look at the dts of the board which most closely resembles your dev-board. Use that as a reference and make changes to the dts according to the differences between the reference board and your dev-board.
Also checkout the following :
- Device-tree Documentation project at eLinux (has a vast collection of links to start reading).
- Series of articles on the basics of device tree.
- Walkthrough of migrating to device-tree.
Minimal reg + interrupt example with QEMU virtual device
Our example will add the following device tree node to the versatilepb device tree which QEMU will use due to -M versatilepb:
lkmc_platform_device#101e9000 {
compatible = "lkmc_platform_device";
reg = <0x101e9000 0x1000>;
interrupts = <18>;
interrupt-controller;
#interrupt-cells = <2>;
clocks = <&pclk>;
clock-names = "apb_pclk";
lkmc-asdf = <0x12345678>;
};
Then, by using a Linux kernel module to interact with the device, we will test the following DTS features:
registers addresses
IRQs
read custom properties from the driver
These are the main components of the example:
Linux versatile .dts patch on Linux fork
reg and interrupt match numbers hard-coded in the QEMU versatile machine (which represents the SoC)
compatible matches the platform_driver.name in the kernel module, and informs the kernel which module will handle this device
we also pass a custom property to the driver: lkmc-asdf = <0x12345678>;, which is read with of_property_read_u32
the device tree is passed to QEMU's firmware with the -dtb argument
QEMU fork:
device that reads a register and generates interrupts
insert device into -M versatilepb
kernel module Writes to memory on probe to test things out, which also generates an IRQ.
Device trees have many more features that we haven't covered, but this example should get you started, and easily allow you to play around with any new features that come up.
Further resources:
indispensable elinux tutorial: http://elinux.org/Device_Tree_Usage
play around with dtc for purely syntaxical questions. E.g., it shows how nodes are simply merged by path: https://unix.stackexchange.com/a/375923/32558
https://unix.stackexchange.com/questions/118683/what-is-a-device-tree-and-a-device-tree-blob
Lets take a example and I will explain each one of them as below
auart0: serial#8006a000 {
compatible = "fsl,imx28-auart", "fsl,imx23-auart";
reg = <0x8006a000 0x2000>;
interrupts = <112>;
dmas = <&dma_apbx 8>, <&dma_apbx 9>;
dma-names = "rx", "tx";
};
Required properties:
- compatible : Should be "fsl,-auart". The supported SoCs include
imx23 and imx28.
- reg : Address and length of the register set for the device
- interrupts : Should contain the auart interrupt numbers
- dmas: DMA specifier, consisting of a phandle to DMA controller node
and AUART DMA channel ID.
- dma-names: "rx" for RX channel, "tx" for TX channel.
Note: Each auart port should have an alias correctly numbered in "aliases"
node.
For more advance properties, please go to this link, it is very useful
Device Tree Explanation
Hope it helps!
Complementary to the other answers:
Keep in mind, that there is also a section for devicetrees in the official kernel source under root/Documentation/devicetree(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree?h=v5.2-rc5).

Resources