Message ID | 20191122082402.18173-25-jiada_wang@mentor.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | atmel_mxt_ts misc | expand |
Hi, I've been testing this patchset on Chromebook equipped with Atmel touchscreen & touchpad. In my setup, this particular patch seems to introduce a regression on firmware update: > localhost /sys/devices/pci0000:00/0000:00:15.0/i2c_designware.0/i2c-6/i2c-ATML0001:00 # echo maxtouch-ts.fw > update_fw > bash: echo: write error: Remote I/O error Kernel logs show that the reason is failed I2C transfer: > [ 111.632131] atmel_mxt_ts i2c-ATML0001:00: Found bootloader addr:27 ID:21 version:4 > [ 111.637711] atmel_mxt_ts i2c-ATML0001:00: Unlocking bootloader > [ 129.155091] atmel_mxt_ts i2c-ATML0001:00: Sent 1356 frames, 212224 bytes > [ 129.263269] atmel_mxt_ts i2c-ATML0001:00: The firmware update succeeded > [ 129.263952] atmel_mxt_ts i2c-ATML0001:00: __mxt_read_chunk: i2c transfer failed (-121) > [ 129.265072] atmel_mxt_ts i2c-ATML0001:00: mxt_bootloader_read: i2c recv failed (-121) > [ 129.265588] atmel_mxt_ts i2c-ATML0001:00: Trying alternate bootloader address > [ 129.266375] atmel_mxt_ts i2c-ATML0001:00: mxt_bootloader_read: i2c recv failed (-121) Surprisingly, only touchscreen device is affected. When I checked out to 119e1b7e8481 ("Input: atmel_mxt_ts - refactor code to enter bootloader into separate func") all worked fine. In between these commits I got some mixed results, including timeout while waiting for completion: > [ 190.006174] atmel_mxt_ts i2c-ATML0001:00: Found bootloader addr:27 ID:21 version:4 > [ 190.317819] atmel_mxt_ts i2c-ATML0001:00: Wait for completion timed out. > [ 190.318267] atmel_mxt_ts i2c-ATML0001:00: Update wait error -110 > [ 190.319310] atmel_mxt_ts i2c-ATML0001:00: Unlocking bootloader > [ 208.369825] atmel_mxt_ts i2c-ATML0001:00: Sent 1356 frames, 212224 bytes > [ 208.536942] atmel_mxt_ts i2c-ATML0001:00: The firmware update succeeded > [ 208.544835] atmel_mxt_ts i2c-ATML0001:00: Family: 164 Variant: 14 Firmware V2.3.AA Objects: 40 > [ 208.547623] atmel_mxt_ts i2c-ATML0001:00: Touchscreen size X4095Y2729 Some more details - the touchscreen device reports itself as: > atmel_mxt_ts i2c-ATML0001:00: Family: 164 Variant: 14 Firmware V2.3.AA Objects: 40 Due to Chromebook limitations on kernel version, I'm running 4.19 kernel with patches backported from master (so that atmel_mxt_ts is aligned between master and 4.19). The platform is Samsung Chromebook Pro. Best regards, Bartosz
Hi Bartosz thanks for the report, I will test firmware update on my chromebook Thanks, Jiada On 2020/01/28 2:41, Bartosz Szczepanek wrote: > Hi, > > I've been testing this patchset on Chromebook equipped with Atmel touchscreen & > touchpad. In my setup, this particular patch seems to introduce a regression > on firmware update: > >> localhost /sys/devices/pci0000:00/0000:00:15.0/i2c_designware.0/i2c-6/i2c-ATML0001:00 # echo maxtouch-ts.fw > update_fw >> bash: echo: write error: Remote I/O error > > Kernel logs show that the reason is failed I2C transfer: > >> [ 111.632131] atmel_mxt_ts i2c-ATML0001:00: Found bootloader addr:27 ID:21 version:4 >> [ 111.637711] atmel_mxt_ts i2c-ATML0001:00: Unlocking bootloader >> [ 129.155091] atmel_mxt_ts i2c-ATML0001:00: Sent 1356 frames, 212224 bytes >> [ 129.263269] atmel_mxt_ts i2c-ATML0001:00: The firmware update succeeded >> [ 129.263952] atmel_mxt_ts i2c-ATML0001:00: __mxt_read_chunk: i2c transfer failed (-121) >> [ 129.265072] atmel_mxt_ts i2c-ATML0001:00: mxt_bootloader_read: i2c recv failed (-121) >> [ 129.265588] atmel_mxt_ts i2c-ATML0001:00: Trying alternate bootloader address >> [ 129.266375] atmel_mxt_ts i2c-ATML0001:00: mxt_bootloader_read: i2c recv failed (-121) > > Surprisingly, only touchscreen device is affected. When I checked out to > 119e1b7e8481 ("Input: atmel_mxt_ts - refactor code to enter bootloader into > separate func") all worked fine. In between these commits I got some mixed > results, including timeout while waiting for completion: > >> [ 190.006174] atmel_mxt_ts i2c-ATML0001:00: Found bootloader addr:27 ID:21 version:4 >> [ 190.317819] atmel_mxt_ts i2c-ATML0001:00: Wait for completion timed out. >> [ 190.318267] atmel_mxt_ts i2c-ATML0001:00: Update wait error -110 >> [ 190.319310] atmel_mxt_ts i2c-ATML0001:00: Unlocking bootloader >> [ 208.369825] atmel_mxt_ts i2c-ATML0001:00: Sent 1356 frames, 212224 bytes >> [ 208.536942] atmel_mxt_ts i2c-ATML0001:00: The firmware update succeeded >> [ 208.544835] atmel_mxt_ts i2c-ATML0001:00: Family: 164 Variant: 14 Firmware V2.3.AA Objects: 40 >> [ 208.547623] atmel_mxt_ts i2c-ATML0001:00: Touchscreen size X4095Y2729 > > Some more details - the touchscreen device reports itself as: > >> atmel_mxt_ts i2c-ATML0001:00: Family: 164 Variant: 14 Firmware V2.3.AA Objects: 40 > > Due to Chromebook limitations on kernel version, I'm running 4.19 kernel > with patches backported from master (so that atmel_mxt_ts is aligned between > master and 4.19). The platform is Samsung Chromebook Pro. > > Best regards, > Bartosz >
Hello Bartosz On 2020/01/28 2:41, Bartosz Szczepanek wrote: > Hi, > > I've been testing this patchset on Chromebook equipped with Atmel touchscreen & > touchpad. In my setup, this particular patch seems to introduce a regression > on firmware update: > >> localhost /sys/devices/pci0000:00/0000:00:15.0/i2c_designware.0/i2c-6/i2c-ATML0001:00 # echo maxtouch-ts.fw > update_fw >> bash: echo: write error: Remote I/O error > > Kernel logs show that the reason is failed I2C transfer: > >> [ 111.632131] atmel_mxt_ts i2c-ATML0001:00: Found bootloader addr:27 ID:21 version:4 >> [ 111.637711] atmel_mxt_ts i2c-ATML0001:00: Unlocking bootloader >> [ 129.155091] atmel_mxt_ts i2c-ATML0001:00: Sent 1356 frames, 212224 bytes >> [ 129.263269] atmel_mxt_ts i2c-ATML0001:00: The firmware update succeeded >> [ 129.263952] atmel_mxt_ts i2c-ATML0001:00: __mxt_read_chunk: i2c transfer failed (-121) >> [ 129.265072] atmel_mxt_ts i2c-ATML0001:00: mxt_bootloader_read: i2c recv failed (-121) >> [ 129.265588] atmel_mxt_ts i2c-ATML0001:00: Trying alternate bootloader address >> [ 129.266375] atmel_mxt_ts i2c-ATML0001:00: mxt_bootloader_read: i2c recv failed (-121) > > Surprisingly, only touchscreen device is affected. When I checked out to > 119e1b7e8481 ("Input: atmel_mxt_ts - refactor code to enter bootloader into > separate func") all worked fine. In between these commits I got some mixed > results, including timeout while waiting for completion: > >> [ 190.006174] atmel_mxt_ts i2c-ATML0001:00: Found bootloader addr:27 ID:21 version:4 >> [ 190.317819] atmel_mxt_ts i2c-ATML0001:00: Wait for completion timed out. >> [ 190.318267] atmel_mxt_ts i2c-ATML0001:00: Update wait error -110 >> [ 190.319310] atmel_mxt_ts i2c-ATML0001:00: Unlocking bootloader >> [ 208.369825] atmel_mxt_ts i2c-ATML0001:00: Sent 1356 frames, 212224 bytes >> [ 208.536942] atmel_mxt_ts i2c-ATML0001:00: The firmware update succeeded >> [ 208.544835] atmel_mxt_ts i2c-ATML0001:00: Family: 164 Variant: 14 Firmware V2.3.AA Objects: 40 >> [ 208.547623] atmel_mxt_ts i2c-ATML0001:00: Touchscreen size X4095Y2729 > > Some more details - the touchscreen device reports itself as: > >> atmel_mxt_ts i2c-ATML0001:00: Family: 164 Variant: 14 Firmware V2.3.AA Objects: 40 > > Due to Chromebook limitations on kernel version, I'm running 4.19 kernel > with patches backported from master (so that atmel_mxt_ts is aligned between > master and 4.19). The platform is Samsung Chromebook Pro. > I have found the root cause for the regression, will submit v7 patch-set shortly, if you could validate for the update, it will be very helpful thanks, Jiada > Best regards, > Bartosz >
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 520dc9670b38..842d407efc86 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -27,6 +27,7 @@ #include <linux/gpio/consumer.h> #include <asm/unaligned.h> #include <linux/regulator/consumer.h> +#include <linux/workqueue.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/videobuf2-v4l2.h> @@ -218,6 +219,7 @@ enum t100_type { #define MXT_REGULATOR_DELAY 150 /* msec */ #define MXT_CHG_DELAY 100 /* msec */ #define MXT_POWERON_DELAY 150 /* msec */ +#define MXT_BOOTLOADER_WAIT 36E5 /* 1 minute */ /* Command to unlock bootloader */ #define MXT_UNLOCK_CMD_MSB 0xaa @@ -299,6 +301,7 @@ struct mxt_fw_frame { /* Firmware update context */ struct mxt_flash { + struct mxt_data *data; const struct firmware *fw; struct mxt_fw_frame *frame; loff_t pos; @@ -306,7 +309,8 @@ struct mxt_flash { unsigned int count; unsigned int retry; u8 previous; - bool complete; + struct completion flash_completion; + struct delayed_work work; }; /* Each client has this additional data */ @@ -355,6 +359,7 @@ struct mxt_data { char *cfg_name; const char *pcfg_name; const char *input_name; + struct mxt_flash *flash; /* Cached parameters from object table */ u16 T5_address; @@ -599,28 +604,17 @@ static int mxt_write_firmware_frame(struct mxt_data *data, struct mxt_flash *f) f->frame_size); } -static int mxt_check_bootloader(struct mxt_data *data, struct mxt_flash *f) +static int mxt_check_bootloader(struct mxt_data *data) { struct device *dev = &data->client->dev; + struct mxt_flash *f = data->flash; u8 state; int ret; - /* - * In application update mode, the interrupt - * line signals state transitions. We must wait for the - * CHG assertion before reading the status byte. - * Once the status byte has been read, the line is deasserted. - */ - ret = mxt_wait_for_completion(data, &data->chg_completion, - MXT_FW_CHG_TIMEOUT); - if (ret) { - /* - * TODO: handle -ERESTARTSYS better by terminating - * fw update process before returning to userspace - * by writing length 0x000 to device (iff we are in - * WAITING_FRAME_DATA state). - */ - dev_warn(dev, "Update wait error %d\n", ret); + /* Handle interrupt after download/flash process */ + if (f->pos >= f->fw->size) { + complete(&f->flash_completion); + return 0; } ret = mxt_bootloader_read(data, &state, 1); @@ -666,14 +660,12 @@ static int mxt_check_bootloader(struct mxt_data *data, struct mxt_flash *f) f->pos += f->frame_size; f->count++; - if (f->pos >= f->fw->size) { - f->complete = true; + if (f->pos >= f->fw->size) dev_info(dev, "Sent %u frames, %zu bytes\n", f->count, f->fw->size); - } else if (f->count % 50 == 0) { + else if (f->count % 50 == 0) dev_dbg(dev, "Sent %u frames, %lld/%zu bytes\n", f->count, f->pos, f->fw->size); - } break; @@ -695,6 +687,9 @@ static int mxt_check_bootloader(struct mxt_data *data, struct mxt_flash *f) f->previous = state; + /* Poll after 0.1s if no interrupt received */ + schedule_delayed_work(&f->work, msecs_to_jiffies(100)); + return 0; unexpected: @@ -1403,7 +1398,11 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) if (data->in_bootloader) { complete(&data->chg_completion); - return IRQ_HANDLED; + + if (data->flash) + cancel_delayed_work_sync(&data->flash->work); + + return IRQ_RETVAL(mxt_check_bootloader(data)); } if (!data->object_table) @@ -3304,16 +3303,13 @@ static int mxt_enter_bootloader(struct mxt_data *data) if (data->suspend_mode == MXT_SUSPEND_REGULATOR) mxt_regulator_enable(data); - if (data->suspend_mode == MXT_SUSPEND_DEEP_SLEEP) - enable_irq(data->irq); - data->suspended = false; } if (!data->in_bootloader) { - /* Change to the bootloader mode */ - data->in_bootloader = true; + disable_irq(data->irq); + /* Change to the bootloader mode */ ret = mxt_t6_command(data, MXT_COMMAND_RESET, MXT_BOOT_VALUE, false); if (ret) @@ -3326,67 +3322,73 @@ static int mxt_enter_bootloader(struct mxt_data *data) if (ret) return ret; + data->in_bootloader = true; mxt_sysfs_remove(data); mxt_free_input_device(data); mxt_free_object_table(data); - } else { - enable_irq(data->irq); } - reinit_completion(&data->chg_completion); + dev_dbg(&data->client->dev, "Entered bootloader\n"); return 0; } +static void mxt_fw_work(struct work_struct *work) +{ + struct mxt_flash *f = + container_of(work, struct mxt_flash, work.work); + + mxt_check_bootloader(f->data); +} + static int mxt_load_fw(struct device *dev) { struct mxt_data *data = dev_get_drvdata(dev); - struct mxt_flash f = { 0, }; int ret; - ret = request_firmware(&f.fw, data->fw_name, dev); + data->flash = devm_kzalloc(dev, sizeof(struct mxt_flash), GFP_KERNEL); + if (!data->flash) + return -ENOMEM; + + data->flash->data = data; + + ret = request_firmware(&data->flash->fw, data->fw_name, dev); if (ret) { dev_err(dev, "Unable to open firmware %s\n", data->fw_name); - return ret; + goto free; } /* Check for incorrect enc file */ - ret = mxt_check_firmware_format(dev, f.fw); + ret = mxt_check_firmware_format(dev, data->flash->fw); if (ret) goto release_firmware; - ret = mxt_enter_bootloader(data); - if (ret) - goto release_firmware; + init_completion(&data->flash->flash_completion); + INIT_DELAYED_WORK(&data->flash->work, mxt_fw_work); + reinit_completion(&data->flash->flash_completion); - while (true) { - ret = mxt_check_bootloader(data, &f); + if (!data->in_bootloader) { + ret = mxt_enter_bootloader(data); if (ret) - return ret; - - if (f.complete) - break; + goto release_firmware; } - /* Wait for flash. */ - ret = mxt_wait_for_completion(data, &data->chg_completion, - MXT_FW_RESET_TIME); - if (ret) - goto disable_irq; + enable_irq(data->irq); + /* Poll after 0.1s if no interrupt received */ + schedule_delayed_work(&data->flash->work, msecs_to_jiffies(100)); - /* - * Wait for device to reset. Some bootloader versions do not assert - * the CHG line after bootloading has finished, so ignore potential - * errors. - */ - mxt_wait_for_completion(data, &data->chg_completion, MXT_FW_RESET_TIME); + /* Wait for flash. */ + ret = mxt_wait_for_completion(data, &data->flash->flash_completion, + MXT_BOOTLOADER_WAIT); - data->in_bootloader = false; -disable_irq: disable_irq(data->irq); + cancel_delayed_work_sync(&data->flash->work); + data->in_bootloader = false; release_firmware: - release_firmware(f.fw); + release_firmware(data->flash->fw); +free: + devm_kfree(dev, data->flash); return ret; }