linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Miroslav Bendík" <miroslav.bendik@gmail.com>
To: "Limonciello, Mario" <mario.limonciello@amd.com>,
	Benjamin Tissoires <btissoir@redhat.com>,
	Hans de Goede <hdegoede@redhat.com>
Cc: Wolfram Sang <wsa@kernel.org>,
	Andrea Ippolito <andrea.ippo@gmail.com>,
	Dmitry Torokhov <dmitry.torokhov@gmail.com>,
	Alex Hung <alex.hung@canonical.com>,
	Linux I2C <linux-i2c@vger.kernel.org>,
	"open list:HID CORE LAYER" <linux-input@vger.kernel.org>,
	Platform Driver <platform-driver-x86@vger.kernel.org>,
	"Shah, Nehal-bakulchandra" <Nehal-bakulchandra.Shah@amd.com>
Subject: Re: Touchpad stickiness on AMD laptops (was Dell Inspiron/XPS)
Date: Sun, 30 Jan 2022 14:14:45 +0100	[thread overview]
Message-ID: <04a38456-8999-36ac-1adc-632b9ba942ad@gmail.com> (raw)
In-Reply-To: <5409e747-0c51-24e2-7ffa-7dd9c8a7aec7@amd.com>

Hello,
i have small status update.

First most important information:
On AMD is trackpoint connected to ASF bus (similar to SMBus, but with
other control registers).

This bus has interrupt. After boot always generates interrupts for each
transaction. After playing it stops generating interrupts for
transaction, i don't know exactly why. More important is, that it can
generate interrupts when receives message from slave to broadcast
address (0x08).

To enable interrupts we should set:

ListenAddr to 0x08 and ListenAddrEn to 1:

outb_p((0x08 << 1) | 0x01, 0x09 + piix4_smba);

Then SlaveIntrListenEn of SlaveEn should be set to 1:

outb_p(inb_p(0x15 + piix4_smba) | 0x02, 0x15 + piix4_smba);

Now funny part, how to read address of slave device
(0x2c for synaptics):

Important register is ASFx13 DataBankSel register. If interrupt is
generated from slave device, then DataBankxFull is set. Address can be
retrieved using block read from 0x07 (DataIndex) register. Before
reading register SetReadHostDataBank should be 0. After setting
DataBankSel i am reading HostControl (dummy read), then reading form
DataIndex value 0x08 (broadcast address) and 0x2c (device, that wanted
attention). I am using following code, but it don't work good. Sometimes
there is bad value, sometimes it's reversed, first read gives 0x2c,
second 0x10. Don't know why. I have looked on decompiled windows driver
from synaptics and it looks, that there is special handling for
different DataBankSel values. I don't know exactly why, but problems are
rare, for now i am ignoring problems.


static u8 read_asf_data_bank(unsigned short piix4_smba, u8 bank_number)
{
     outb_p(bank_number << 4, 0x13 + piix4_smba);
     inb_p(0x02 + piix4_smba); // reset DataIndex
     inb_p(0x07 + piix4_smba); // read SMBus broadcast address
     return inb_p(0x07 + piix4_smba);
}


static irqreturn_t piix4_isr(int irq, void *dev_id)
{
     //struct i2c_adapter *piix4_adapter = (struct i2c_adapter *)dev_id;
     //struct i2c_piix4_adapdata *adapdata = 
i2c_get_adapdata(piix4_adapter);
     unsigned short piix4_smba = 0xb20;

     u8 bank_sel;
     u8 address[2] = {0x00, 0x00};
     u8 *current_address;

     current_address = &address[0];

     bank_sel = inb_p(0x13 + piix4_smba); // DataBankSel

     if ((bank_sel & 0x0c) == 0x00) { // bits DataBankxFull not set
         return IRQ_HANDLED;
     }

     printk(KERN_INFO "Bank=%02x\n", bank_sel);

     if ((bank_sel & 0x01) == 0) { // Last touched bank is 0
         if (bank_sel & 0x08) {
             *current_address = read_asf_data_bank(piix4_smba, 1);
             current_address++;
         }
         if (bank_sel & 0x04) {
             *current_address = read_asf_data_bank(piix4_smba, 0);
         }
     }
     else { // Last touched bank is 1
         if (bank_sel & 0x04) {
             *current_address = read_asf_data_bank(piix4_smba, 0);
             current_address++;
         }
         if (bank_sel & 0x08) {
             *current_address = read_asf_data_bank(piix4_smba, 1);
         }
     }

     outb_p(bank_sel & 0x0c, 0x13 + piix4_smba); // Clear DataBankxFull

     printk(KERN_INFO "Address=%02x %02x\n", address[0] >> 1, address[1] 
 >> 1);

     if (address[0] != 0x00) {
         i2c_handle_smbus_host_notify(piix4_aux_adapter, address[0] >> 1);
     }
     if (address[1] != 0x00 && address[1] != address[0]) {
         i2c_handle_smbus_host_notify(piix4_aux_adapter, address[1] >> 1);
     }

     return IRQ_HANDLED;
}

Now, when i load module i see this in log:

i2c i2c-11: Error: no response!
rmi4_f12 rmi4-00.fn12: Failed to read object data. Code: -6.
Bank=8d
Address=2c 2c
input input92: rmi_2d_sensor_abs_report: obj[0]: type: 0x01 X: 323 Y: 
301 Z: 79 WX: 9 WY: 2
Bank=8d
Address=2c 2c
input input92: rmi_2d_sensor_abs_report: obj[0]: type: 0x01 X: 271 Y: 
378 Z: 73 WX: 8 WY: 4
Bank=8d
Address=2c 2c
input input92: rmi_2d_sensor_abs_report: obj[0]: type: 0x01 X: 468 Y: 
378 Z: 72 WX: 7 WY: 3
Bank=8d
Address=2c 2c
i2c i2c-11: Bus collision! SMBus may be locked until next hard reset. 
(sorry!)
rmi4_f12 rmi4-00.fn12: Failed to read object data. Code: -5.
Bank=8d
Address=2c 2c
input input92: rmi_2d_sensor_abs_report: obj[0]: type: 0x01 X: 563 Y: 
373 Z: 73 WX: 7 WY: 2
Bank=8d
Address=2c 2c
i2c i2c-11: Bus collision! SMBus may be locked until next hard reset. 
(sorry!)
rmi4_f12 rmi4-00.fn12: Failed to read object data. Code: -5.


There are too many bus collisions a no responses. This is my
implementation of piix4_access_asf

static s32 piix4_access_asf(struct i2c_adapter *adap, u16 addr,
          unsigned short flags, char read_write,
          u8 command, int size, union i2c_smbus_data *data)
{
     struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
     unsigned short piix4_smba = adapdata->smba;
     int timeout = 0;
     int retval;
     u8 temp;

     // Acquire IMC semaphore
     outb_p(0x01, 0x14 + piix4_smba);
     while ((++timeout < MAX_TIMEOUT) && (!((temp = inb_p(0x14 + 
piix4_smba)) & 0x01))) {
         usleep_range(250, 500);
     }
     if ((temp & 0x01) == 0) {
         printk(KERN_INFO "lock not acquired\n");
         return -EBUSY;
     }

     outb_p(0x80, 0x13 + piix4_smba); // Set DataBankSel to host bank

     retval = piix4_access(adap, addr, flags, read_write, command, size, 
data);

     // Release semphore
     outb_p(0x02, 0x14 + piix4_smba);

     return retval;
}

Before transaction i am requesting HostSemaphore. Semaphore is correctly
acquired. Always. I don't know how exactly i should avoid bus conflicts.

Interrupts are sometimes generated with low frequency, sometimes with
high frequency. I don't know exactly why. Frequency changes after
restart of psmouse driver. Frequency changes with touch activity too, if
starts generating with high frequency and then i don't touch anything,
then frequency goes down. After touchpad activity frequency again goes
up.

Here is video with current state:

https://youtu.be/tf850B7UTWA

  parent reply	other threads:[~2022-01-30 13:14 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CAGhUXvBw4rzCQrqttyyS=Psxmhppk79c6fDoxPbV91jE7fO_9A@mail.gmail.com>
2021-08-27  6:57 ` Touchpad stickiness on Dell Inspiron/XPS Andrea Ippolito
2021-09-23  8:47   ` Andrea Ippolito
2021-09-23  9:00     ` Hans de Goede
2021-09-23  9:06       ` Andrea Ippolito
2022-01-06 13:14       ` Wolfram Sang
2022-01-11 10:34         ` Touchpad stickiness on AMD laptops (was Dell Inspiron/XPS) Hans de Goede
2022-01-11 11:13           ` Benjamin Tissoires
2022-01-11 23:15             ` Limonciello, Mario
2022-01-12  8:33               ` Wolfram Sang
2022-01-12 12:21                 ` Miroslav Bendík
2022-01-12 22:54                   ` Limonciello, Mario
2022-01-15  9:39                     ` Miroslav Bendík
2022-01-15 13:46                       ` Limonciello, Mario
2022-01-15 18:10                         ` Miroslav Bendík
2022-01-17  8:39                         ` Miroslav Bendík
2022-01-17  9:08                           ` Hans de Goede
2022-01-23 17:25                             ` Miroslav Bendík
2022-01-12 12:31                 ` Hans de Goede
2022-01-30 13:14               ` Miroslav Bendík [this message]
2022-02-06 18:13               ` Miroslav Bendík

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=04a38456-8999-36ac-1adc-632b9ba942ad@gmail.com \
    --to=miroslav.bendik@gmail.com \
    --cc=Nehal-bakulchandra.Shah@amd.com \
    --cc=alex.hung@canonical.com \
    --cc=andrea.ippo@gmail.com \
    --cc=btissoir@redhat.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=hdegoede@redhat.com \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=mario.limonciello@amd.com \
    --cc=platform-driver-x86@vger.kernel.org \
    --cc=wsa@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).