HiKey960 device tree query for SPI slaves

I apologize if this topic has been discussed before.
I am trying to bring up a SPI slave on HiKey 960 Low Speed Expansion (J2002). I have connected GPIO 209 (pin 24) as the interrupt line and corresponding entries are made in the dts file:

arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
@@ -670,6 +670,12 @@
/* On Low speed expansion */
label = “LS-SPI0”;
status = “okay”;

  •    compatible = "spi_driver";
    
  •    spi-max-frequency = <1000000>;
    
  •    reg = <0>;
    
  •   interrupt-parent = <&gpio27>;
    
  •    interrupts = <209 1>;
    

};

After flashing the board with a boot image (generated after building the dtb files from kernel build and copying over to AOSP_ROOT/device/ and running make bootimage), I do not see the interrupt number 209 in /proc/interrupts. I don’t see GPIO_297 as the interrupt either, if I assume that GPIO 209 is represented as GPIO 297 in kernel (as per that pin mapping table for HiKey 960).
Following is the result from cat /proc/interrupts:

       CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       

4: 6431 5239 4615 4055 5186 4588 4465 4077 GIC-0 27 Level arch_timer
6: 0 0 0 0 0 0 0 0 GIC-0 80 Level timer
7: 0 0 0 0 0 0 0 0 GIC-0 56 Level arm-pmu
8: 0 0 0 0 0 0 0 0 GIC-0 57 Level arm-pmu
9: 0 0 0 0 0 0 0 0 GIC-0 58 Level arm-pmu
10: 0 0 0 0 0 0 0 0 GIC-0 59 Level arm-pmu
11: 0 0 0 0 0 0 0 0 GIC-0 34 Level arm-pmu
12: 0 0 0 0 0 0 0 0 GIC-0 35 Level arm-pmu
13: 0 0 0 0 0 0 0 0 GIC-0 36 Level arm-pmu
14: 0 0 0 0 0 0 0 0 GIC-0 37 Level arm-pmu
18: 0 0 0 0 0 0 0 0 GIC-0 150 Level ffd71000.i2c
19: 370 0 0 0 0 0 0 0 GIC-0 151 Level ffd72000.i2c
20: 0 0 0 0 0 0 0 0 GIC-0 346 Level fdf0b000.i2c
22: 350 0 0 0 0 0 0 0 GIC-0 109 Level uart-pl011
23: 1 0 0 0 0 0 0 0 GIC-0 111 Level uart-pl011
24: 287 0 0 0 0 0 0 0 GIC-0 175 Level k3-dma
25: 0 0 0 0 0 0 0 0 GIC-0 248 Level k3-dma
26: 0 0 0 0 0 0 0 0 GIC-0 78 Level rtc-pl031
56: 0 0 0 0 0 0 0 0 GIC-0 344 Level pl022
58: 5894 0 0 0 0 0 0 0 GIC-0 310 Level ufshcd
59: 0 0 0 0 0 0 0 0 GIC-0 171 Level dw-mci
60: 323 0 0 0 0 0 0 0 GIC-0 172 Level dw-mci
63: 0 0 0 0 0 0 0 0 GIC-0 177 Level hisi_thermal
64: 0 0 0 0 0 0 0 0 GIC-0 290 Level e82c0000.mali
65: 0 0 0 0 0 0 0 0 GIC-0 291 Level e82c0000.mali
66: 29 0 0 0 0 0 0 0 GIC-0 292 Level e82c0000.mali

The spi2 connector has this entry in the (hi3660-hikey960.dtsi) file:
spi2: spi@ffd68000 {
compatible = “arm,pl022”, “arm,primecell”;
reg = <0x0 0xffd68000 0x0 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&crg_ctrl HI3660_CLK_GATE_SPI2>;
clock-names = “apb_pclk”;
pinctrl-names = “default”;
pinctrl-0 = <&spi2_pmx_func>;
num-cs = <1>;
cs-gpios = <&gpio27 2 0>;
status = “disabled”;

I would have expected to see an entry like ffd68000.spi2 (something similar to any of the i2c entries, GIC-0 346 Level fdf0b000.i2c…) in the above /proc/interrupts table.

Clearly, the kernel didn’t detect the SPI device (kernel driver complains that the SPI device wasn’t configured correctly). What am I missing?

I am not sure if Pin 209 is under interrupt-parent gpio26 or gpio27 (from arch/arm64/boot/dts/hisilicon/hi3660.dtsi, it appears to be under gpio26 but the spi2: spi@ffd68000 entry in the above dtsi file shows that the spi2 will have interrupts under gpio27. In the end I tried both the options, once with gpio26 and another time with gpio27, but still didn’t see the device detected in the device tree.

Any pointer will be highly appreciated. Thanks much.

The controller driver request interrupt with “pl022” name:

56: 0 0 0 0 0 0 0 0 GIC-0 344 Level pl022

Can you share you dts via e.g. pastebin, from what you attached you do not define you spi device as a child node of the spi controller.

Thanks a lot for your information. I have declared the spi slave as a child node under the controller, spi2. When I compile the kernel, I get following warning, not sure if it is harmless:

  CALL    scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  DTC     arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dtb
arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dtb: Warning (interrupts_property): /soc/spi@ffd68000:#interrupt-cells: size is (12), expected multiple of 8
  Building modules, stage 2.
  MODPOST 3 modules
  DTC     arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dtb
arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dtb: Warning (interrupts_property): /soc/spi@ffd68000:#interrupt-cells: size is (12), expected multiple of 8
  CAT     arch/arm64/boot/Image.gz-dtb

I have uploaded the dts file in pastebin (https://pastebin.com/SUP5f49a).

Here’s the device tree entries as I read from the kernel
(using find /proc/device-tree/ -type f -exec head {} +):


soc

==> /proc/device-tree/soc/spi@ffd68000/pinctrl-names <==

default

==> /proc/device-tree/soc/spi@ffd68000/#address-cells <==

==> /proc/device-tree/soc/spi@ffd68000/num-cs <==

==> /proc/device-tree/soc/spi@ffd68000/pinctrl-0 <==

>

==> /proc/device-tree/soc/spi@ffd68000/clock-names <==

apb_pclk

==> /proc/device-tree/soc/spi@ffd68000/interrupts <==

t

==> /proc/device-tree/soc/spi@ffd68000/clocks <==

==> /proc/device-tree/soc/spi@ffd68000/ndp10x@0/interrupts <==

?

==> /proc/device-tree/soc/spi@ffd68000/ndp10x@0/spi-max-frequency <==

B@

==> /proc/device-tree/soc/spi@ffd68000/ndp10x@0/compatible <==

ndp10x_spi_driver

==> /proc/device-tree/soc/spi@ffd68000/ndp10x@0/reg <==

==> /proc/device-tree/soc/spi@ffd68000/ndp10x@0/name <==

ndp10x

==> /proc/device-tree/soc/spi@ffd68000/#size-cells <==

==> /proc/device-tree/soc/spi@ffd68000/interrupt-parent <==

"

==> /proc/device-tree/soc/spi@ffd68000/label <==

LS-SPI0

==> /proc/device-tree/soc/spi@ffd68000/compatible <==

arm,pl022arm,primecell

==> /proc/device-tree/soc/spi@ffd68000/status <==

okay

==> /proc/device-tree/soc/spi@ffd68000/reg <==

?ր

==> /proc/device-tree/soc/spi@ffd68000/name <==

spi

==> /proc/device-tree/soc/spi@ffd68000/cs-gpios <==

"

==> /proc/device-tree/soc/gpio@fff10000/clock-names <==

apb_pclk

==> /proc/device-tree/soc/gpio@fff10000/gpio-controller <==

==> /proc/device-tree/soc/gpio@fff10000/gpio-line-names <==

[SPI0_DIN][SPI0_DOUT][SPI0_CS]GPIO_219_CC_INTNCNC[PMU_INT]

As for kernel code that does request_irq, it looks like as follows:

static int
ndp10x_spi_probe(struct spi_device *spi)
{
s = spi_setup(spi);
s = request_threaded_irq(spi->irq, NULL,
ndp10x_isr, flags, DEVICE_NAME, d);
}

On my /proc/interrupts table, I do not see that the driver got the interrupt, the table still looks like:

56: 0 0 0 0 0 0 0 0 GIC-0 344 Level pl022

Are you saying that I should use 344 instead of spi->irq in the above code? I still see SPI configuration failure in dmesg

&spi2 {
    /* On Low speed expansion */
    label = "LS-SPI0";
    status = "okay";
    interrupt-parent = <&gpio27>;
    ndp10x@0 {
           compatible = "ndp10x_spi_driver";
           spi-max-frequency = <1000000>;
           reg = <0>;
           interrupts = <209 1>;
    };

You should move the interrupt-parent node from the SPI controller node (&spi2) to your device node. The GIC 344 interrupt is an internal interrupt linked to the SPI controller and has nothing to do with your specific SPI device (ndp10x).

The interrupt will appear only when your SPI device driver will request the interrupt to register and handler. The spi driver is the one which will match the “ndp10x_spi_driver” compatible string. This is not an upstream driver, so I assume you implemented it?

Ok, after moving the interrupt-parent to ndp10x@0, I do see the interrupts showing up in /proc/

56: 0 0 0 0 0 0 0 0 GIC-0 148 Level pl022
57: 0 0 0 0 0 0 0 0 GIC-0 344 Level pl022

But the driver failed to acquire the interrupt:
[ 53.163938] ndp10x_spi_probe: failed to acquire irq 0

spi->irq is 0.

The driver is not upstreamed yet. At this point, I am wondering if that failure is due to wrong configuration in driver or still something else missing in dts. The same driver code works fine on Raspberry Pi boards, so the interrupt configuration etc. are already tested (on Pi).

I have irq flags set as : IRQF_ONESHOT | IRQF_TRIGGER_RISING

If something else is still missing on dts side, please let me know. Thanks a lot.

What appears to me is that request for irq #209 from the dts seems to be invalid:

60.516609] error: hwirq 0xd1 is too large for :soc:gpio@fff0f000

I looked at the parent interrupt-group, gpio26, which has following:

&gpio26 {
        /* GPIO_208-GPIO_215 */
        gpio-line-names =
                "GPIO-A", /* LSEC pin 23: GPIO_208 */
                "GPIO-B", /* LSEC pin 24: GPIO_209 */
                "GPIO-C", /* LSEC pin 25: GPIO_210 */
                "GPIO-D", /* LSEC pin 26: GPIO_211 */
                "GPIO-E", /* LSEC pin 27: GPIO_212 */
                "[PCIE_CLKREQ_N]",
                "[PCIE_WAKE_N]",
                "[SPI0_CLK]"; /* LSEC pin 8: SPI2_CLK */
};
&spi2 {
        /* On Low speed expansion */
        label = "LS-SPI0";
        status = "okay";
        ndp10x@0 {
                compatible = "ndp10x_spi_driver";
                spi-max-frequency = <1000000>;
                reg = <0>;
                interrupts = <209 1>;
                interrupt-parent = <&gpio26>;
and in the hi3660.dtsi file:
                spi2: spi@ffd68000 {
                        compatible = "arm,pl022", "arm,primecell";
                        reg = <0x0 0xffd68000 0x0 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <0>;
                        interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&crg_ctrl HI3660_CLK_GATE_SPI2>;
                        clock-names = "apb_pclk";
                        pinctrl-names = "default";
                        pinctrl-0 = <&spi2_pmx_func>;
                        num-cs = <1>;
                        cs-gpios = <&gpio26 2 0>;
                        status = "disabled";
                };

and the gpio26 is defined as:

                gpio26: gpio@fff0f000 {
                        compatible = "arm,pl061", "arm,primecell";
                        reg = <0 0xfff0f000 0 0x1000>;
                        interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
                        gpio-controller;
                        #gpio-cells = <2>;
                        /* GPIO208 */
                        gpio-ranges = <&pmx4 0 28 8>;  <---if this is the range, then 
                                                 209 may be invalid??
                        interrupt-controller;
                        #interrupt-cells = <2>;
                        clocks = <&sctrl HI3660_PCLK_AO_GPIO4>;
                        clock-names = "apb_pclk";
                };

I am not sure how kernel maps this to the interrupt pins. So, the key is to use the right pin number for interrupt configuration.
Another thing… how do I flash the kernel image on to the board? I modfied the kernel/irq/irqdomain.c: irq_domain_associate() to see whats the maximum value of the irq that the domain can allocate, since it is failing at the following code:

        if (WARN(hwirq >= domain->hwirq_max,
-                "error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name))

What bothers me is that flashing boot.img doesn’t update the kernel on the device at all.

Interrupt numbers in DT are based on the interrupt number as it appears at the interrupt parent. In the case of GPIO device this usually means the 16 or 32 pins managed by the GPIO controller.

So based on gpio-line-names (but not much other knowledge about Hikey960 :wink: ) I suggest changing the first cell of interrupts from 209 to 1.

As a matter of fact, I tried that earlier, and I got a different error:

   31.495887] ndp10x: spi_setup
[   31.498869] ndp10x: spi_irq_number: 76
[   31.505835] gpio gpiochip26: (fff0f000.gpio): gpiochip_lock_as_irq: tried to flag a GPIO set as output for IRQ
[   31.515877] gpio gpiochip26: (fff0f000.gpio): unable to lock HW IRQ 1 for IRQ
[   31.523029] genirq: Failed to request resources for ndp10x (irq 76) on irqchip fff0f000.gpio
[   31.531577] ndp10x_spi_probe: failed to acquire irq 76
[   31.536740] ndp10x_spi_driver: probe of spi0.0 failed with error -5

So, that <1 1> instead of <209 1> actually, was mapped to irq 76 by kernel. Really don’t know what is the right pin number. Besides, is there a way to update the kernel image in AOSP build? I am building kernel separately and copying the Image.gz-dtb-4.19 and hi3660-hikey960.dtb-4.19 to AOSP root and running make bootimage from there to create boot.img. Now, flashing this boot.img is not updating the kernel on HiKey960… What am I missing?
Thanks.

The IRQ number can usually be considered meaningless… they are dynamically allocated based on whatever resources are present in the device tree.

I’d suggest looking more closely at “tried to flag a GPIO set as output for IRQ” since this looks like a promising lead. You can use ‘git grep’ to find out exactly why this comes out but, to me, it looks like the GPIO code is declining to allocate pin 1 as an interrupt because it is configured as an output.

Regarding the kernel update what do you mean by coping to AOSP root? (the clearest answer is probably sharing the exact commands you used to do the copy)

My dir layout:
/scratch/android
art/
bionic/

hikey-linaro/
arch/
block/
drivers/
mm/
etc…

Ok, following is my script to build the kernel and copy over Image and dtb to AOSP root:

AOSP_ROOT =/scratch/android
mPATH =$AOSP_ROOT/prebuilts/clang/host/linux-x86/clang-r353983c/bin:$AOSP_ROOT/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin
PATH =$mPATH:$PATH make TARGET_KERNEL_USE =4.19 ARCH =arm64 CC =clang CLANG_TRIPLE =aarch64-linux-gnu- CROSS_COMPILE =aarch64-linux-android-

cp arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dtb …/device/linaro/hikey-kernel/hi3660-hikey960.dtb-4.19
cp arch/arm64/boot/Image.gz-dtb …/device/linaro/hikey-kernel/Image.gz-dtb-4.19

and then run,
rm out/target/product/hikey960/*.img
make bootimage (from AOSP_ROOT)

this produces {boot,dt}.img in out/target/product/hikey960/

Looks to me like you have the filename for the kernel wrong (I think you are overwriting the hikey620 kernel image instead of the hikey960 version).

Interrupt 4 worked. I can see that the driver claimed interrupt successfully. Thanks for pointing out the lead.
So, I am setting it up as <4 1>

Not sure what above points to wrong board name. I am generating the image as 960, for sure. Note that the driver binaries are correctly updated.

As I said, you have got the filename for the kernel wrong:
cp arch/arm64/boot/Image.gz-dtb …/device/linaro/hikey-kernel/Image.gz-dtb-4.19

Image.gz-dtb-4.19 is the hikey620 kernel, the hikey960 kernel has hikey960 somewhere in the filename (but I don’t currently have the docs open so I can’t remember where).

Copy hi3660-hikey960.dtb (arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dtb) to the aosp/device/linaro/hikey-kernel directory as file: hi3660-hikey960.dtb-4.19

Copy the Image file (arch/arm64/boot/Image.gz-dtb) to the aosp/device/linaro/hikey-kernel directory as file: Image.gz-dtb-hikey960-4.19

We can refer to the doc [1], though its commands are using kernel 4.9.

[1] https://source.android.com/setup/build/devices

Thats exactly what I did, and still it didn’t reflect the changes.

Delete ALL of the files *.dtb, kernel, boot.img, dt.img from your out/…/ path.