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

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

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