@@ -305,6 +305,8 @@ struct mxt_flash {
size_t frame_size;
unsigned int count;
unsigned int retry;
+ u8 previous;
+ bool complete;
};
/* Each client has this additional data */
@@ -583,64 +585,121 @@ static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address)
return 0;
}
-static int mxt_check_bootloader(struct mxt_data *data, unsigned int state,
- bool wait)
+static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock);
+
+static int mxt_write_firmware_frame(struct mxt_data *data, struct mxt_flash *f)
+{
+ f->frame = (struct mxt_fw_frame *)(f->fw->data + f->pos);
+
+ /* Take account of CRC bytes */
+ f->frame_size = __be16_to_cpu(f->frame->size) + 2U;
+
+ /* Write one frame to device */
+ return mxt_bootloader_write(data, f->fw->data + f->pos,
+ f->frame_size);
+}
+
+static int mxt_check_bootloader(struct mxt_data *data, struct mxt_flash *f)
{
struct device *dev = &data->client->dev;
- u8 val;
+ u8 state;
int ret;
-recheck:
- if (wait) {
+ /*
+ * 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->bl_completion,
+ MXT_FW_CHG_TIMEOUT);
+ if (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.
+ * 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).
*/
- ret = mxt_wait_for_completion(data, &data->bl_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_err(dev, "Update wait error %d\n", ret);
- return ret;
- }
+ dev_warn(dev, "Update wait error %d\n", ret);
}
- ret = mxt_bootloader_read(data, &val, 1);
+ ret = mxt_bootloader_read(data, &state, 1);
if (ret)
return ret;
+ /* Remove don't care bits */
+ if (state & ~MXT_BOOT_STATUS_MASK)
+ state &= ~MXT_BOOT_STATUS_MASK;
+
switch (state) {
case MXT_WAITING_BOOTLOAD_CMD:
+ dev_info(dev, "Unlocking bootloader\n");
+ ret = mxt_send_bootloader_cmd(data, true);
+ if (ret)
+ return ret;
+
+ break;
+
case MXT_WAITING_FRAME_DATA:
- case MXT_APP_CRC_FAIL:
- val &= ~MXT_BOOT_STATUS_MASK;
+ if ((f->previous != MXT_WAITING_BOOTLOAD_CMD)
+ && (f->previous != MXT_FRAME_CRC_PASS)
+ && (f->previous != MXT_FRAME_CRC_FAIL))
+ goto unexpected;
+
+ ret = mxt_write_firmware_frame(data, f);
+ if (ret)
+ return ret;
+
+ break;
+
+ case MXT_FRAME_CRC_CHECK:
+ if (f->previous != MXT_WAITING_FRAME_DATA)
+ goto unexpected;
break;
+
case MXT_FRAME_CRC_PASS:
- if (val == MXT_FRAME_CRC_CHECK) {
- goto recheck;
- } else if (val == MXT_FRAME_CRC_FAIL) {
- dev_err(dev, "Bootloader CRC fail\n");
- return -EINVAL;
+ if (f->previous != MXT_FRAME_CRC_CHECK)
+ goto unexpected;
+
+ /* Next frame */
+ f->retry = 0;
+ f->pos += f->frame_size;
+ f->count++;
+
+ if (f->pos >= f->fw->size) {
+ f->complete = true;
+ dev_info(dev, "Sent %u frames, %zu bytes\n",
+ f->count, f->fw->size);
+ } else if (f->count % 50 == 0) {
+ dev_dbg(dev, "Sent %u frames, %lld/%zu bytes\n",
+ f->count, f->pos, f->fw->size);
}
+
+ break;
+
+ case MXT_FRAME_CRC_FAIL:
+ if (f->retry > 20) {
+ dev_err(dev, "Retry count exceeded\n");
+ return -EIO;
+ }
+
+ /* Back off by 20ms per retry */
+ dev_dbg(dev, "Bootloader frame CRC failure\n");
+ f->retry++;
+ msleep(f->retry * 20);
break;
+
default:
return -EINVAL;
}
- if (val != state) {
- dev_err(dev, "Invalid bootloader state %02X != %02X\n",
- val, state);
- return -EINVAL;
- }
+ f->previous = state;
return 0;
+
+unexpected:
+ dev_err(dev, "Unexpected state transition\n");
+ return -EINVAL;
}
static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
@@ -3301,57 +3360,13 @@ static int mxt_load_fw(struct device *dev)
if (ret)
goto release_firmware;
- ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false);
- if (ret) {
- /* Bootloader may still be unlocked from previous attempt */
- ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false);
- if (ret)
- goto disable_irq;
- } else {
- dev_info(dev, "Unlocking bootloader\n");
-
- /* Unlock bootloader */
- ret = mxt_send_bootloader_cmd(data, true);
+ while (true) {
+ ret = mxt_check_bootloader(data, &f);
if (ret)
- goto disable_irq;
- }
-
- while (f.pos < f.fw->size) {
- f.frame = (struct mxt_fw_frame *)(f.fw->data + f.pos);
-
- ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true);
- if (ret)
- goto disable_irq;
-
- /* Take account of CRC bytes */
- f.frame_size = __be16_to_cpu(f.frame->size) + 2U;
-
- /* Write one frame to device */
- ret = mxt_bootloader_write(data, f.fw->data + f.pos,
- f.frame_size);
- if (ret)
- goto disable_irq;
-
- ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true);
- if (ret) {
- f.retry++;
-
- /* Back off by 20ms per retry */
- msleep(f.retry * 20);
-
- if (f.retry > 20) {
- dev_err(dev, "Retry count exceeded\n");
- goto disable_irq;
- }
- } else {
- f.retry = 0;
- f.pos += f.frame_size;
- f.count++;
- }
+ return ret;
- if (f.count % 50 == 0)
- dev_dbg(dev, "Sent %u frames, %lld/%zu bytes\n",
- f.count, f.pos, f.fw->size);
+ if (f.complete)
+ break;
}
/* Wait for flash. */
@@ -3360,7 +3375,6 @@ static int mxt_load_fw(struct device *dev)
if (ret)
goto disable_irq;
- dev_dbg(dev, "Sent %u frames, %lld bytes\n", f.count, f.pos);
/*
* Wait for device to reset. Some bootloader versions do not assert
@@ -3370,7 +3384,6 @@ static int mxt_load_fw(struct device *dev)
mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME);
data->in_bootloader = false;
-
disable_irq:
disable_irq(data->irq);
release_firmware: