#interrupt-cells is 2 but interrupts is a 3-tuple - linux

I was looking at the device tree for the Beagle Bone Black and started with am57xx-beagle-x15.dts. Drilling down into dra7.dtsi I found gpio1:
gpio1: gpio#4ae10000 {
compatible = "ti,omap4-gpio";
reg = <0x4ae10000 0x200>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "gpio1";
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
I had read that #interrupt-cells gave the number of u32s or cells that one would expect in an item in the the interrupts list. But when I look at interrupts I see a 3-tuple: <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>. Would love to know, why does this contain 3 cells and not 2?

It's a very late answer but add one so that someone could get help.
I can't find the exact dts file from my current linux 5.15 source. But the interrupt-parent of the node should have required 3 cells for the interrupts property. For gic, normally it requires 3 values - {interrupt type, interrupt number, flag}. It's in the device binding document of gic (Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml in linux 5.15)
"#interrupt-cells":
const: 3
description: |
The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
interrupts.
The 2nd cell contains the interrupt number for the interrupt type.
SPI interrupts are in the range [0-987]. PPI interrupts are in the
range [0-15].
The 3rd cell is the flags, encoded as follows:
bits[3:0] trigger type and level flags.
1 = low-to-high edge triggered
2 = high-to-low edge triggered (invalid for SPIs)
4 = active high level-sensitive
8 = active low level-sensitive (invalid for SPIs).
bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of
the 8 possible cpus attached to the GIC. A bit set to '1' indicated
the interrupt is wired to that CPU. Only valid for PPI interrupts.
Also note that the configurability of PPI interrupts is IMPLEMENTATION
DEFINED and as such not guaranteed to be present (most SoC available
in 2014 seem to ignore the setting of this flag and use the hardware
default value).

Related

How to set GPIO pin output value in device tree

I am using an iMX6 based board and I'd like to set the GPIO value of an arbirtrary ouput to 1 or 0 at boot using the Device Tree.
Is it possible and how can I do that?
I wonder if I have to rely on the gpio-leds feature or if I can define a new node in the DT.
I found some topics on the internet saying I can do as below but doesn't work.
test {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_leds>;
myout {
label = "myoutlabel";
gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
pinctrl_gpio_leds: gpioledsgrp {
fsl,pins = <
MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x80000000 // My output
>;
};
Any hint would be appreciated.
TIA
You can enable/disable the internal Pull-Up/Pull-Down resistor (along with other electrical characteristics) that is attached to that pin, thus forcing a logic 1/0 in the pin. You should seek the "pad control register" for that pad (IOMUXC_SW_PAD_CTL_PAD_GPIO_8) in the processor reference manual, and then look which characteristics you wish to enable/disable by setting the right bits to 1 or 0, as needed, in the aforementioned register. However, I'm not sure if this is exactly what you're looking for.
Maybe this can help to understand the operation: http://cache.freescale.com/files/32bit/doc/app_note/AN5078.pdf

How to reserve Linux's memory for a single driver

I am running a secure OS in the ARM Trustzone, along side Linux which is running in the "normal" world. Since some part of the RAM is protected by hardware from access by the normal world (using a TZASC), I want to prevent Linux to try to access it otherwise it will crash. I also need a shared buffer between the two world, allocated by Linux. To this purpose, I want to reserve two memory regions, using this document.
I have two kind of areas:
the first one is a static one and I don't want to ever touch it
the second one is a dynamic one and I only want a single driver to be able to modify its content.
Here is an extract of my device tree:
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
/* global autoconfigured region for contiguous allocations */
linux,cma {
compatible = "shared-dma-pool";
reusable;
reg = <0 0xa0000000 0 0x14000000>;
linux,cma-default;
};
/* First range, static, that I don't want anyone to touch */
reserved_static: mymem#0xc0000000 {
compatible = "mymem,reserved-memory";
reg = <0 0xc0000000 0 0x08000000>;
no-map;
};
/* Second range, limited to a single driver */
reserved_dynamic: shared {
compatible = "mymem,memory-shared";
size = <0 0x08000000>;
alignment = <0 0x200000>;
alloc-ranges = <0 0xc8000000 0 0x38000000>;
};
};
mydev {
compatible = "mydev,mydev";
memory-region = <&reserved_dynamic>;
};
I can access the device tree information from my driver code, and I would like to prevent any access to the static memory range (I think I got that one covered with the no-map attribute), and also that only my driver is able to access the dynamic one.
Is this possible, and how can I achieve it ?

Linux interrupt is not handled by the wrapper driver

I am writing a device specific DMA driver for Zynq AXI DMA. The driver is actually a wrapper driver and uses Xilinx DMA driver under the DMA engine driver framework like this:
+------------------+
| Wrapper driver |
+------------------+
| DMA framework |
+------------------+
| Xilinx DMA Driver|
+------------------+
+ Kernel +
+------------------+
I use interrupt 61 for transfer complete and 62 for receive complete. The interrupt handler for Xilinx DMA driver is properly installed (I checked /proc/interrupts). However, I the driver seems not to handle the interrupt properly by showing me this:
I checked /proc/interrupts. IRQ62 is not handled. Here is the code where the interrupt is registered:
0986 /* find the IRQ line, if it exists in the device tree */
0987 chan->irq = irq_of_parse_and_map(node, 0);
0988 err = devm_request_irq(xdev->dev, chan->irq, dma_intr_handler,
0989 IRQF_SHARED,
0990 "xilinx-dma-controller", chan);
And here is the output of cat /proc/interrupt:
I have two questions:
1) If I only install interrupt handler for Xilinx DMA driver but not the wrapper driver, while I use the wrapper driver as the char device, interrupt will not be handled by the Xilinx DMA driver?
2) If so, how do I let Xilinx DMA driver to handle the interrupt in this case? Is 'irqpoll' the only solution? Is there any performance issue compared to direct interrupt handling rather than polling?
Your devicetree isn't good, more precisely, your pl.dtsi file. My pl file looks like this:
amba_pl: amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;
axi_dma_0: dma#40400000 {
compatible = "xlnx,axi-dma";
interrupt-parent = <&intc>;
interrupts = <0 29 4 0 30 4>;
reg = <0x40400000 0x10000>;
xlnx,include-sg ;
dma-channel#40400000 {
compatible = "xlnx,axi-dma-mm2s-channel";
interrupts = <0 29 4>;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x0>;
};
dma-channel#40400030 {
compatible = "xlnx,axi-dma-s2mm-channel";
interrupts = <0 30 4>;
xlnx,datawidth = <0x20>;
xlnx,device-id = <0x0>;
};
};
};

Understanding the Device Tree mechanism

Was reading the Device Tree Usage and reached to the section describing the ranges key attribute for a node.
external-bus {
#address-cells = <2>
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
ethernet#0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
interrupts = < 5 2 >;
};
i2c#1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
interrupts = < 6 2 >;
rtc#58 {
compatible = "maxim,ds1338";
reg = <58>;
interrupts = < 7 3 >;
};
};
flash#2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
What is the difference between ranges and reg ?
What are the dimensions for the ranges, how the parser figure out what is written in it?
One missing part I didn't understand yet? Can't include .h files instead of hard-coding values in a the .dts file?
The "range" property maps one or more addresses (the second number from the left of the range) in the current node, the "external bus" node, to addresses in the parent node (probably the CPU) address space (the third number in the range). The fourth number is the length of the range. Buses can have their own idea of addresses on their external side to which peripherals are attached, so the drivers that manage the peripherals on the bus will need to know these ranges in order to read to or write from the the devices.
The "reg" property indicates the address at which a device resides in the address range of the node (the "external bus" in this case) in which the device is defined. So in this case, flash#2,0 resides at address 0 in the external bus range, and extends to address 0x04000000. This corresponds to address range 0x30000000 to 0x34000000 in the parent (CPU) address space.
I am assuming that the length specifier of the third range, 2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash should in fact be 0x04000000 rather than 0x1000000.
For this perticular example, Jonathan Ben-Avraham's explanation is correct. But its good to understand the detailed structure of ranges property in device tree.
ranges is a list of address translations.
Each entry in the ranges table is a tuple containing the child
address, the parent address, and the size of the region in the child
address space.
like
ranges = < Child1Address ParentAddressForChild1 sizeofchild1
Child2Address ParentAddressForChild2 sizeofchild2
Child3Address ParentAddressForChild3 sizeofchild3
>;
The size of each field is determined as below
For taking the child Address size check #address-cells value of child node.
For taling the the parent address size check #address-cells value of its parent node,
For taking the length of size check #size-cells value of child node.
Exampe1: Mentioned in as Question
#address-cells = <1>;
#size-cells = <1>;
external-bus {
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
Let's decode first entry.
Child address-cells size is 2 so first two entry mention child address. (This address is specific to local child addressing only)
Further how to decode these 2 entry are device specific. Device driver should have documentation for these)
parent address-cells size is 1 so next entry is of parent address for that child.
child size-cells is 1 so next entry is of child's range (wrt to parent address.)
Exampe2: PCI device entry
#address-cells = <1>;
#size-cells = <1>;
pci#0x10180000 {
compatible = "arm,versatile-pci-hostbridge", "pci";
reg = <0x10180000 0x1000>;
interrupts = <8 0>;
bus-range = <0 0>;
#address-cells = <3>
#size-cells = <2>;
ranges = <0x42000000 0 0x80000000 0x80000000 0 0x20000000
0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
Here
0x42000000 0 0x80000000 is the address of child1. How to decode these 3 entry is mentioned in PCI driver documentation.
0x80000000 is the parent address. Parent node is cpu so from cpu this address is used to talk to this devide.
0 0x20000000 is the size of this device in parent address space. (0 to 512MB of address)

generating EXTI0 interrupt when extenal temperature sensor is connected to STM32F207VC

I am using STM32F207VC controller . I have my external probe temperature sensor connected to one of the internal ADC channel of stm32.
I want to generate an external interrupt when this is connected to controller and i should start measuring from external temperature sensor.
Please could any one provide me code or any help in this
Thanks
I have an STM32F4 processor interfaced with a Solomon Systems SSD1963 GPU. The GPU has a Tearing Signal (TE) that notifies the processor when it is about to do a vertical refresh. I hope you can use this code as an example and adapt it to your solution.
The TE signal is connected to the CPU's GPIO G7 pin. So first I have to configure the GPIO pin.
//GPIO Pin G7
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOG, &GPIO_InitStructure);
Next I have to configure the interrupt and NVIC.
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOG, EXTI_PinSource7);
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_StructInit(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = EXTI_Line7;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
Finally I have to create the interrupt handler. The EXTI9_5_IRQHandler handles external interrupts on lines 5 ~ 7. This method is actually defined in my CPUs startup assembly file as a weak reference. I just need to redefine the method and the linker will do the rest.
extern "C" void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line7) != RESET)
{
//Handle the interrupt
EXTI_ClearITPendingBit(EXTI_Line7);
}
}
I'm using Mentor Graphics' Sourcery Codebench Lite as my toolchain.

Resources