Thread (20 messages) 20 messages, 7 authors, 2022-02-06

Re: Touchpad stickiness on AMD laptops (was Dell Inspiron/XPS)

flat view

From: Miroslav Bendík <hidden>
Date: 2022-02-06 18:13:13
Also in: linux-i2c, platform-driver-x86

Hello,
feature host notify is now implemented. Trackpoint / touchpad is working pretty stable with high sample rate. But ... i can't disable interrupts.
It can generatete 10 000 interrupts/s in extreme case with loaded pinctrl_amd when device is idle. But it works: https://youtu.be/L4oKt500kNo

SMBus is probably implemented correctly. It looks, like RMI4 is sending notifications constantly, even when interrupt bits are clean.

Attached patch is full of hacks, i warn anyone who would like to use it, i am not responsible for any hardware damage and hard-coded values like interrupt number should be changed manually.

Now more details:

Windows driver is fully interrupt driven. Therefore i tried to implement interrupt driven transaction. This was pretty easy. First implemented function was quick write.

I thought that interrupt is triggered after each transaction. After first transaction no interrupt was triggered. Each next transaction triggered interrupt 7us after starting transaction. This was impossible, because quick write contains 10 bits (start, 7 bit address, r/w and ack) transferred at 100kHz (readed from PM register AsfClkSel). Minimum time is 100us. Interrupt was generated after cleaning of interrupt bit or after disabling device. IRQ 7 has probably wrong type / polarity.

Lets look at relevant section of DSDT:

Scope (_SB.PCI0)
{
    Device (SMB1)
    {
        Name (_HID, "SMB0001")  // _HID: Hardware ID
        Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
        {
            IO (Decode16,
                0x0B20,             // Range Minimum
                0x0B20,             // Range Maximum
                0x20,               // Alignment
                0x20,               // Length
                )
            IRQ (Level, ActiveLow, Shared, )
                {7}
        })
        Method (_STA, 0, NotSerialized)  // _STA: Status
        {
            Return (0x0F)
        }
    }
}

Interrupt 7 is level triggered and has active low state (standard value for PCI). Now lets look at /proc/interrupts

IR-IO-APIC    2-edge      timer
IR-IO-APIC    1-edge      i8042
IR-IO-APIC    7-edge      piix4_smbus
IR-IO-APIC    8-edge      rtc0
IR-IO-APIC    9-fasteoi   acpi
IR-IO-APIC   10-edge      AMDI0010:00
IR-IO-APIC   11-edge      AMDI0010:01
IR-IO-APIC   12-edge      i8042

This probably happens at signal level:

- r reset host interrupt status
- s start transaction
- e end transaction

11111111111111111111111111      111111111111111111
                         0      1                0
                         0      1                0
                         0      1                0
                         00000000                0000000
        |     |          |      |     |          |
       r-1   s-1        e-1    r-2   s-2        e-2

Interrupt is triggered on rising edge (r-2). I have tried to set type / polarity using devm_request_irq / irq_set_irq_type, but this has no effect. Temporary i have written hack to arch/x86/kernel/apic/io_apic.c:

if (mp_irq_entries == 7) {
    m->irqflag = MP_IRQPOL_ACTIVE_LOW | MP_IRQTRIG_LEVEL;
}

Now interrupt are triggered at right time with correct polarity.

PCI uses level triggered interrupts. Interrupt flags must be cleared. When there is not cleared interrupt flag, then interrupt will be triggered again and again. ASF has two interrupt flags: HostStatus.Intr and AsfStatus.SlaveIntr.

There is no problem with HostStatus.Intr. On slave event AsfStatus contains value 0x40 (6th bit set) instead of 0x20 (from documentation). Writing to 0x40 clears pending interrupt, 0x20 not. Disassembled windows driver writes to 0x40. AMD should fix this register in documentation.

Now i can load psmouse synaptics_intertouch=1 and device works great. Moving cursor causes bus collisions and device permanently sends host notify messages (cca 300 events / s), but it's stable.

After unloading psmouse or waiting few minutes device stops sending interrupts. After touching device interrupts are generated again. When i am not touching touchpad, interrupt status register contains zero, but host notifications are generated long time after last touch and with very high frequency. Interrupts are generated even when i don't call i2c_handle_smbus_host_notify. It can't be cause of infinite loop.

Now i don't know why RMI4 sends constantly notifications. I don't have current documentation (my documentation don't contains any new function like F03). Maybe there is new method to clear interrupts..

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help