From a584e3c44bcadb4365b05d260856483ed5b2b5a1 Mon Sep 17 00:00:00 2001 From: zhuangnk1 Date: Mon, 30 Oct 2023 14:58:58 +0800 Subject: [PATCH] Update UWB driver to version 7.4 Update UWB driver to version 7.4 to support 1.2v platform Change-Id: Iace483f72aeba6deaacd9cd91cb844aabbaa279f Signed-off-by: zhuangnk1 Reviewed-on: https://gerrit.mot.com/2778728 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Tao Sun Submit-Approved: Jira Key --- drivers/uwb/qm35/debug.c | 55 --- drivers/uwb/qm35/debug.h | 6 - drivers/uwb/qm35/debug_qmrom.c | 127 ++--- drivers/uwb/qm35/hsspi.c | 14 +- drivers/uwb/qm35/hsspi.h | 18 +- drivers/uwb/qm35/hsspi_coredump.c | 72 +-- drivers/uwb/qm35/hsspi_coredump.h | 46 +- drivers/uwb/qm35/hsspi_log.c | 16 +- drivers/uwb/qm35/libfwupdater/src/fwupdater.c | 358 +++++++++----- .../uwb/qm35/libqmrom/src/qm357xx_rom_b0.c | 4 +- .../uwb/qm35/libqmrom/src/qm357xx_rom_c0.c | 81 +++- .../qm35/libqmrom/src/qm357xx_rom_common.c | 37 +- drivers/uwb/qm35/libqmrom/src/qmrom_common.c | 7 +- drivers/uwb/qm35/qm35-spi.c | 445 +++++++++++++----- drivers/uwb/qm35/qm35.h | 16 +- drivers/uwb/qm35/qm35_coredump_ioctls.h | 14 + drivers/uwb/qm35/qmrom_spi.c | 19 +- drivers/uwb/qm35/uci_ioctls.h | 15 +- include/linux/uwb/fwupdater.h | 15 +- include/linux/uwb/qm357xx_rom.h | 2 + include/linux/uwb/qmrom.h | 7 +- include/linux/uwb/qmrom_spi.h | 3 +- 22 files changed, 932 insertions(+), 445 deletions(-) create mode 100644 drivers/uwb/qm35/qm35_coredump_ioctls.h diff --git a/drivers/uwb/qm35/debug.c b/drivers/uwb/qm35/debug.c index af66a65c08e2..2092babf6c6c 100644 --- a/drivers/uwb/qm35/debug.c +++ b/drivers/uwb/qm35/debug.c @@ -145,12 +145,10 @@ static ssize_t debug_traces_read(struct file *filp, char __user *buff, { char *entry; rb_entry_size_t entry_size; - //struct qm35_ctx *qm35_hdl; uint16_t ret; struct debug *debug; debug = priv_from_file(filp); - //qm35_hdl = container_of(debug, struct qm35_ctx, debug); if (!debug->trace_ops) return -ENOSYS; @@ -233,46 +231,6 @@ static int debug_traces_release(struct inode *inodep, struct file *filep) return 0; } -static ssize_t debug_coredump_read(struct file *filep, char __user *buff, - size_t count, loff_t *off) -{ - //struct qm35_ctx *qm35_hdl; - struct debug *debug; - char *cd; - size_t cd_len = 0; - - debug = priv_from_file(filep); - //qm35_hdl = container_of(debug, struct qm35_ctx, debug); - - if (!debug->coredump_ops) - return -ENOSYS; - - cd = debug->coredump_ops->coredump_get(debug, &cd_len); - - return simple_read_from_buffer(buff, count, off, cd, cd_len); -} - -static ssize_t debug_coredump_write(struct file *filp, const char __user *buff, - size_t count, loff_t *off) -{ - struct debug *debug; - u8 force; - - debug = priv_from_file(filp); - - if (kstrtou8_from_user(buff, count, 10, &force)) - return -EFAULT; - - if (debug->coredump_ops && force != 0) - debug->coredump_ops->coredump_force(debug); - else if (force == 0) - pr_warn("qm35: write non null value to force coredump\n"); - else - return -ENOSYS; - - return count; -} - static ssize_t debug_hw_reset_write(struct file *filp, const char __user *buff, size_t count, loff_t *off) { @@ -326,12 +284,6 @@ static const struct file_operations debug_traces_fops = { .llseek = no_llseek, }; -static const struct file_operations debug_coredump_fops = { - .owner = THIS_MODULE, - .read = debug_coredump_read, - .write = debug_coredump_write, -}; - static const struct file_operations debug_hw_reset_fops = { .owner = THIS_MODULE, .write = debug_hw_reset_write, @@ -481,13 +433,6 @@ int debug_init(struct debug *debug) goto unregister; } - file = debugfs_create_file("coredump", 0444, debug->fw_dir, debug, - &debug_coredump_fops); - if (!file) { - pr_err("qm35: failed to create /sys/kernel/debug/uwb0/fw/coredump\n"); - goto unregister; - } - file = debugfs_create_file("test_sleep_hsspi_ms", 0200, debug->fw_dir, debug, &debug_test_hsspi_sleep_fops); if (!file) { diff --git a/drivers/uwb/qm35/debug.h b/drivers/uwb/qm35/debug.h index 6c78cc211fb9..d105d1fad41d 100644 --- a/drivers/uwb/qm35/debug.h +++ b/drivers/uwb/qm35/debug.h @@ -50,17 +50,11 @@ struct debug_trace_ops { int (*get_soc_id)(struct debug *dbg, uint8_t *soc_id); }; -struct debug_coredump_ops { - char *(*coredump_get)(struct debug *dbg, size_t *len); - int (*coredump_force)(struct debug *dbg); -}; - struct debug { struct dentry *root_dir; struct dentry *fw_dir; struct dentry *chip_dir; const struct debug_trace_ops *trace_ops; - const struct debug_coredump_ops *coredump_ops; struct wait_queue_head wq; struct file *pv_filp; struct mutex pv_filp_lock; diff --git a/drivers/uwb/qm35/debug_qmrom.c b/drivers/uwb/qm35/debug_qmrom.c index c1899c534386..7f39c961fcf2 100644 --- a/drivers/uwb/qm35/debug_qmrom.c +++ b/drivers/uwb/qm35/debug_qmrom.c @@ -25,6 +25,7 @@ * QM35 LOG layer HSSPI Protocol */ +#include #include #include #include @@ -46,8 +47,6 @@ #include "qm35.h" #include "debug.h" -#define FWUPDATER_SPI_SPEED_HZ 20000000 - extern int fu_spi_speed_hz; extern int qmrom_spi_speed_hz; @@ -65,11 +64,18 @@ static struct qm35_ctx *rom_test_prepare(struct file *filp) qm35_hsspi_stop(qm35_hdl); qmrom_set_log_device(&qm35_hdl->spi->dev, LOG_DBG); + + enable_irq(qm35_hdl->ss_rdy_irq); + + qm35_hdl->flashing = true; return qm35_hdl; } static void rom_test_unprepare(struct qm35_ctx *qm35_hdl) { + disable_irq_nosync(qm35_hdl->ss_rdy_irq); + + qm35_hdl->flashing = false; qmrom_set_log_device(&qm35_hdl->spi->dev, LOG_WARN); qm35_hsspi_start(qm35_hdl); } @@ -88,12 +94,12 @@ static struct firmware *file2firmware(const char *filename) filename, 0, (void **)&firmware->data, INT_MAX, &firmware->size, READING_FIRMWARE); if (bytes_read < 0) { - pr_err("kernel_read_file_from_path(%s) returned %d\n", + pr_err("qm35: kernel_read_file_from_path(%s) returned %d\n", filename, (int)bytes_read); goto fail; } if (bytes_read != firmware->size) { - pr_err("kernel_read_file_from_path returned %zu; expected %zu\n", + pr_err("qm35: kernel_read_file_from_path returned %zu; expected %zu\n", bytes_read, firmware->size); goto fail; } @@ -106,7 +112,7 @@ static struct firmware *file2firmware(const char *filename) &size, INT_MAX, READING_FIRMWARE); if (ret < 0) { - pr_err("kernel_read_file_from_path(%s) returned %d\n", + pr_err("qm35: kernel_read_file_from_path(%s) returned %d\n", filename, ret); goto fail; } @@ -114,8 +120,8 @@ static struct firmware *file2firmware(const char *filename) } #endif - print_hex_dump(KERN_DEBUG, "Bin file:", DUMP_PREFIX_ADDRESS, 16, 1, - firmware->data, 16, false); + print_hex_dump(KERN_DEBUG, "qm35: Bin file:", DUMP_PREFIX_ADDRESS, 16, + 1, firmware->data, 16, false); return firmware; fail: @@ -133,24 +139,24 @@ static ssize_t rom_probe(struct file *filp, const char __user *buff, struct qm35_ctx *qm35_hdl = rom_test_prepare(filp); struct qmrom_handle *h; - pr_info("Starting the probe test...\n"); - h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl->gpio_ss_rdy, - qmrom_spi_speed_hz, QMROM_RETRIES, + pr_info("qm35: Starting the probe test...\n"); + h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl, + qm35_hdl->gpio_ss_irq, qmrom_spi_speed_hz, QMROM_RETRIES, qmrom_spi_reset_device, DEVICE_GEN_QM357XX); if (!h) { - pr_err("qmrom_init failed\n"); + pr_err("qm35: qmrom_init failed\n"); goto end; } - pr_info("chip_revision %#2x\n", h->chip_rev); - pr_info("device version %#02x\n", h->device_version); + pr_info("qm35: chip_revision %#2x\n", h->chip_rev); + pr_info("qm35: device version %#02x\n", h->device_version); if (h->chip_rev != 0xa001) { - pr_info("lcs_state %u\n", h->qm357xx_soc_info.lcs_state); - print_hex_dump(KERN_DEBUG, "soc_id:", DUMP_PREFIX_NONE, 16, 1, - h->qm357xx_soc_info.soc_id, + pr_info("qm35: lcs_state %u\n", h->qm357xx_soc_info.lcs_state); + print_hex_dump(KERN_DEBUG, "qm35: soc_id:", DUMP_PREFIX_NONE, + 16, 1, h->qm357xx_soc_info.soc_id, sizeof(h->qm357xx_soc_info.soc_id), false); - print_hex_dump(KERN_DEBUG, "uuid:", DUMP_PREFIX_NONE, 16, 1, - h->qm357xx_soc_info.uuid, + print_hex_dump(KERN_DEBUG, "qm35: uuid:", DUMP_PREFIX_NONE, 16, + 1, h->qm357xx_soc_info.uuid, sizeof(h->qm357xx_soc_info.uuid), false); } qmrom_deinit(h); @@ -179,15 +185,15 @@ static ssize_t rom_flash_dbg_cert(struct file *filp, const char __user *buff, err = copy_from_user(filename, buff, count); if (err) { - pr_err("copy_from_user failed with error %d\n", err); + pr_err("qm35: copy_from_user failed with error %d\n", err); count = err; goto end; } filename[count - 1] = '\0'; certificate = file2firmware(filename); if (!certificate || certificate->size != DEBUG_CERTIFICATE_SIZE) { - pr_err("%s: file retrieval failed, abort (%s)\n", __func__, - certificate ? "wrong size" : "not found"); + pr_err("qm35: %s: file retrieval failed, abort (%s)\n", + __func__, certificate ? "wrong size" : "not found"); count = -1; goto end; } @@ -195,21 +201,24 @@ static ssize_t rom_flash_dbg_cert(struct file *filp, const char __user *buff, /* Flash the debug certificate */ pr_info("Flashing debug certificate %s...\n", filename); - h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl->gpio_ss_rdy, - qmrom_spi_speed_hz, QMROM_RETRIES, + h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl, + qm35_hdl->gpio_ss_irq, qmrom_spi_speed_hz, QMROM_RETRIES, qmrom_spi_reset_device, DEVICE_GEN_QM357XX); if (!h) { - pr_err("qmrom_init failed\n"); + pr_err("qm35: qmrom_init failed\n"); goto end; } err = qm357xx_rom_flash_dbg_cert(h, certificate); if (err) - pr_err("Flashing debug certificate %s failed with %d!\n", + pr_err("qm35: Flashing debug certificate %s failed with %d!\n", filename, err); else - pr_info("Flashing debug certificate %s succeeded!\n", filename); + pr_info("qm35: Flashing debug certificate %s succeeded!\n", + filename); end: + if (filename) + kfree(filename); if (h) qmrom_deinit(h); if (certificate) { @@ -231,20 +240,21 @@ static ssize_t rom_erase_dbg_cert(struct file *filp, const char __user *buff, struct qmrom_handle *h = NULL; int err; - pr_info("Erasing debug certificate...\n"); + pr_info("qm35: Erasing debug certificate...\n"); - h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl->gpio_ss_rdy, - qmrom_spi_speed_hz, QMROM_RETRIES, + h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl, + qm35_hdl->gpio_ss_irq, qmrom_spi_speed_hz, QMROM_RETRIES, qmrom_spi_reset_device, DEVICE_GEN_QM357XX); if (!h) { - pr_err("qmrom_init failed\n"); + pr_err("qm35: qmrom_init failed\n"); goto end; } err = qm357xx_rom_erase_dbg_cert(h); if (err) - pr_err("Erasing debug certificate failed with %d!\n", err); + pr_err("qm35: Erasing debug certificate failed with %d!\n", + err); else - pr_info("Erasing debug certificate succeeded!\n"); + pr_info("qm35: Erasing debug certificate succeeded!\n"); end: if (h) @@ -274,34 +284,33 @@ static ssize_t rom_flash_fw(struct file *filp, const char __user *buff, rc = copy_from_user(filename, buff, count); if (rc) { - pr_err("copy_from_user failed with error %d\n", rc); + pr_err("qm35: copy_from_user failed with error %d\n", rc); goto end; } filename[count - 1] = '\0'; fw = file2firmware(filename); if (!fw) { - pr_err("%s: file %s retrieval failed, abort\n", __func__, + pr_err("qm35: %s: file %s retrieval failed, abort\n", __func__, filename); - rc = -1; goto end; } - pr_info("Flashing image %s (%pK->data %pK)...\n", filename, fw, + pr_info("qm35: Flashing image %s (%pK->data %pK)...\n", filename, fw, fw->data); - h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl->gpio_ss_rdy, - qmrom_spi_speed_hz, QMROM_RETRIES, + h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl, + qm35_hdl->gpio_ss_irq, qmrom_spi_speed_hz, QMROM_RETRIES, qmrom_spi_reset_device, DEVICE_GEN_QM357XX); if (!h) { - pr_err("qmrom_init failed\n"); - rc = -1; + pr_err("qm35: qmrom_init failed\n"); goto end; } rc = qm357xx_rom_flash_fw(h, fw); if (rc) - pr_err("Flashing firmware %s failed with %d!\n", filename, rc); + pr_err("qm35: Flashing firmware %s failed with %d!\n", filename, + rc); else - pr_info("Flashing firmware %s succeeded!\n", filename); + pr_info("qm35: Flashing firmware %s succeeded!\n", filename); end: kfree(filename); @@ -336,52 +345,52 @@ static ssize_t rom_flash_fw_pkg(struct file *filp, const char __user *buff, } rc = copy_from_user(filename, buff, count); if (rc) { - pr_err("copy_from_user failed with error %d\n", rc); + pr_err("qm35: copy_from_user failed with error %d\n", rc); goto end; } filename[count - 1] = '\0'; fw = file2firmware(filename); if (!fw || !fw->data) { - pr_err("%s: file %s retrieval failed (%s), abort\n", __func__, - filename, fw ? "no data read" : "not found"); - rc = -1; + pr_err("qm35: %s file %s retrieval failed (%s), abort\n", + __func__, filename, fw ? "no data read" : "not found"); goto end; } - pr_info("Flashing fw_updater...\n"); - - h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl->gpio_ss_rdy, - qmrom_spi_speed_hz, QMROM_RETRIES, + pr_info("qm35: Flashing fw_updater...\n"); + h = qmrom_init(&qm35_hdl->spi->dev, qm35_hdl, qm35_hdl, + qm35_hdl->gpio_ss_irq, qmrom_spi_speed_hz, QMROM_RETRIES, qmrom_spi_reset_device, DEVICE_GEN_QM357XX); if (!h) { - pr_err("qmrom_init failed\n"); - rc = -1; + pr_err("qm35: qmrom_init failed\n"); goto end; } + h->skip_check_fw_boot = true; rc = qm357xx_rom_flash_fw(h, fw); + h->skip_check_fw_boot = false; if (rc) { - pr_err("Flashing fw_updater failed with %d!\n", rc); + pr_err("qm35: Flashing fw_updater failed with %d!\n", rc); goto end; } - pr_info("Flashing fw_updater succeeded, flashing the fw package now...\n"); + pr_info("qm35: Flashing fw_updater succeeded, flashing the fw package now...\n"); qmrom_spi_set_freq(fu_spi_speed_hz); rc = qm357xx_rom_fw_macro_pkg_get_fw_idx(fw, 1, &fw_size, &fw_data); if (rc) { - pr_err("%s: FW MACRO PACKAGE corupted = %d\n", __func__, rc); + pr_err("qm35: %s FW MACRO PACKAGE corupted = %d\n", __func__, + rc); goto end; } if (*(uint32_t *)fw_data == CRYPTO_FIRMWARE_PACK_MAGIC_VALUE) { - run_fwupdater(h, fw_data, fw_size); + rc = run_fwupdater(h, fw_data, fw_size); } else { - rc = -EINVAL; - pr_err("FW PACKAGE not found - %04x! fw_size = %d\n", + pr_err("qm35: FW PACKAGE not found - %04x! fw_size = %d\n", *(uint32_t *)fw_data, fw_size); goto end; } - pr_info("FW package flashing done, rebooting the QM...\n"); + pr_info("qm35: FW package flashing %s (rc = %d), rebooting the QM...\n", + rc ? "failed" : "succeeded", rc); end: qmrom_spi_reset_device(qm35_hdl); diff --git a/drivers/uwb/qm35/hsspi.c b/drivers/uwb/qm35/hsspi.c index f063a3a4c5d3..174540de3a3b 100644 --- a/drivers/uwb/qm35/hsspi.c +++ b/drivers/uwb/qm35/hsspi.c @@ -141,6 +141,8 @@ static int hsspi_wait_ss_ready(struct hsspi *hsspi) { int ret; + hsspi->waiting_ss_rdy = true; + if (!test_bit(HSSPI_FLAGS_SS_BUSY, hsspi->flags)) { /* The ss_ready went low, so the fw is not busy anymore, * if the ss_ready is high, we can proceed, else, @@ -180,6 +182,8 @@ static int hsspi_wait_ss_ready(struct hsspi *hsspi) */ if (!gpiod_get_value(hsspi->gpio_ss_rdy)) return -EAGAIN; + + hsspi->waiting_ss_rdy = false; return 0; } @@ -270,6 +274,7 @@ static int spi_xfer(struct hsspi *hsspi, const void *tx, void *rx, hsspi->soc->flags); } + hsspi->waiting_ss_rdy = false; return ret; } @@ -376,7 +381,8 @@ static int hsspi_tx(struct hsspi *hsspi, struct hsspi_layer *layer, /* Ignore tx check flags */ check_soc_flag(&hsspi->spi->dev, __func__, hsspi->soc->flags, true); - if (hsspi->host->flags & STC_HOST_PRD) + if ((hsspi->host->flags & STC_HOST_PRD) && + (hsspi->soc->flags & STC_SOC_ODW)) return hsspi_rx(hsspi, hsspi->soc->ul, hsspi->soc->length); return ret; @@ -406,7 +412,11 @@ static int hsspi_pre_read(struct hsspi *hsspi) /* Ignore pre-read check flags */ check_soc_flag(&hsspi->spi->dev, __func__, hsspi->soc->flags, true); - return hsspi_rx(hsspi, hsspi->soc->ul, hsspi->soc->length); + if (hsspi->soc->flags & STC_SOC_ODW) + return hsspi_rx(hsspi, hsspi->soc->ul, hsspi->soc->length); + else + /* Pre-read error. Maybe FW is a little late to setup HSSPI header. */ + return -1; } /** diff --git a/drivers/uwb/qm35/hsspi.h b/drivers/uwb/qm35/hsspi.h index 89fe7e360108..784b44dbd70a 100644 --- a/drivers/uwb/qm35/hsspi.h +++ b/drivers/uwb/qm35/hsspi.h @@ -36,13 +36,15 @@ #include #include -enum { UL_RESERVED, - UL_BOOT_FLASH, - UL_UCI_APP, - UL_COREDUMP, - UL_LOG, - UL_TEST_HSSPI, - UL_MAX_IDX }; +enum { + UL_RESERVED, + UL_BOOT_FLASH, + UL_UCI_APP, + UL_COREDUMP, + UL_LOG, + UL_TEST_HSSPI, + UL_MAX_IDX +}; struct stc_header { u8 flags; @@ -172,6 +174,8 @@ struct hsspi { struct gpio_desc *gpio_ss_rdy; struct gpio_desc *gpio_exton; + + volatile bool waiting_ss_rdy; }; /** diff --git a/drivers/uwb/qm35/hsspi_coredump.c b/drivers/uwb/qm35/hsspi_coredump.c index f163ec79323c..d8250cd119ec 100644 --- a/drivers/uwb/qm35/hsspi_coredump.c +++ b/drivers/uwb/qm35/hsspi_coredump.c @@ -114,7 +114,7 @@ static uint16_t coredump_get_checksum(struct coredump_layer *layer) return crc; } -static void corredump_on_expired_timer(struct timer_list *timer) +static void coredump_on_expired_timer(struct timer_list *timer) { struct coredump_layer *layer = container_of(timer, struct coredump_layer, timer); @@ -234,7 +234,8 @@ static void coredump_received(struct hsspi_layer *hlayer, break; case COREDUMP_BODY_NTF: - pr_info("qm35: coredump: saving coredump data with len: %d [%d/%d]\n", + pr_debug( + "qm35: coredump: saving coredump data with len: %d [%d/%d]\n", cch_body_size, layer->coredump_data_wr_idx + cch_body_size, layer->coredump_size); @@ -253,6 +254,8 @@ static void coredump_received(struct hsspi_layer *hlayer, coredump_send_rcv_status(layer, layer->coredump_status); + if (layer->coredump_status == COREDUMP_RCV_ACK) + wake_up_interruptible(&layer->wq); break; } @@ -289,18 +292,27 @@ static const struct hsspi_layer_ops coredump_ops = { .sent = coredump_sent, }; -char *debug_coredump_get(struct debug *dbg, size_t *len) +void coredump_layer_init(struct coredump_layer *layer) { - char *data; - struct qm35_ctx *qm35_hdl = container_of(dbg, struct qm35_ctx, debug); - - *len = qm35_hdl->coredump_layer.coredump_data_wr_idx; - data = qm35_hdl->coredump_layer.coredump_data; - - return data; + layer->hlayer.name = "QM35 COREDUMP"; + layer->hlayer.id = UL_COREDUMP; + layer->hlayer.ops = &coredump_ops; + layer->coredump_data = NULL; + layer->coredump_data_wr_idx = 0; + layer->coredump_size = 0; + layer->coredump_crc = 0; + layer->coredump_status = 0; + init_waitqueue_head(&layer->wq); + timer_setup(&layer->timer, coredump_on_expired_timer, 0); } -int debug_coredump_force(struct debug *dbg) +void coredump_layer_deinit(struct coredump_layer *layer) +{ + wake_up_interruptible(&layer->wq); + kfree(layer->coredump_data); +} + +bool coredump_layer_force_coredump(struct coredump_layer *coredump) { struct coredump_packet *p; struct coredump_common_hdr hdr = { .cmd_id = COREDUMP_FORCE_CMD }; @@ -308,7 +320,7 @@ int debug_coredump_force(struct debug *dbg) pr_info("qm35: force coredump"); - qm35_hdl = container_of(dbg, struct qm35_ctx, debug); + qm35_hdl = container_of(coredump, struct qm35_ctx, coredump_layer); p = coredump_packet_alloc(sizeof(hdr)); if (!p) @@ -320,30 +332,22 @@ int debug_coredump_force(struct debug *dbg) &p->blk); } -static const struct debug_coredump_ops debug_coredump_ops = { - .coredump_get = debug_coredump_get, - .coredump_force = debug_coredump_force, -}; - -int coredump_layer_init(struct coredump_layer *layer, struct debug *debug) +bool coredump_layer_new_coredump_available(struct coredump_layer *coredump) { - layer->hlayer.name = "QM35 COREDUMP"; - layer->hlayer.id = UL_COREDUMP; - layer->hlayer.ops = &coredump_ops; - - layer->coredump_data = NULL; - layer->coredump_data_wr_idx = 0; - layer->coredump_size = 0; - layer->coredump_crc = 0; - layer->coredump_status = 0; - timer_setup(&layer->timer, corredump_on_expired_timer, 0); - - debug->coredump_ops = &debug_coredump_ops; - - return 0; + return coredump->coredump_status == COREDUMP_RCV_ACK; } -void coredump_layer_deinit(struct coredump_layer *layer) +uint8_t *coredump_layer_get_coredump(struct coredump_layer *coredump) { - kfree(layer->coredump_data); + return coredump->coredump_data; +} + +uint32_t coredump_layer_get_coredump_size(struct coredump_layer *coredump) +{ + return coredump->coredump_data_wr_idx; +} + +void coredump_layer_reset_status(struct coredump_layer *coredump) +{ + coredump->coredump_status = COREDUMP_RCV_NACK; } diff --git a/drivers/uwb/qm35/hsspi_coredump.h b/drivers/uwb/qm35/hsspi_coredump.h index c7403fcdce5b..2c81f7d864e2 100644 --- a/drivers/uwb/qm35/hsspi_coredump.h +++ b/drivers/uwb/qm35/hsspi_coredump.h @@ -29,11 +29,11 @@ #ifndef __HSSPI_COREDUMP_H__ #define __HSSPI_COREDUMP_H__ +#include #include #include #include "hsspi.h" -#include "debug.h" struct coredump_packet { struct hsspi_block blk; @@ -47,9 +47,51 @@ struct coredump_layer { uint16_t coredump_crc; uint8_t coredump_status; struct timer_list timer; + wait_queue_head_t wq; }; -int coredump_layer_init(struct coredump_layer *coredump, struct debug *debug); +void coredump_layer_init(struct coredump_layer *coredump); void coredump_layer_deinit(struct coredump_layer *coredump); +/** + * coredump_layer_force_coredump() - force coredump + * @coredump: pointer to &struct coredump_layer + * + * Return: true if ok, false otherwise. + */ +bool coredump_layer_force_coredump(struct coredump_layer *coredump); + +/** + * coredump_layer_new_coredump_available() - checks if the layer has + * ack coredump data to be read + * @coredump: pointer to &struct coredump_layer + * + * Return: true if coredump is available, false otherwise. + */ +bool coredump_layer_new_coredump_available(struct coredump_layer *coredump); + +/** + * coredump_layer_get_coredump() - get coredump + * @coredump: pointer to &struct coredump_layer + * + * Return: a &uint8_t pointing to the coredump data if succeed, NULL otherwise + */ +uint8_t *coredump_layer_get_coredump(struct coredump_layer *coredump); + +/** + * coredump_layer_get_coredump_size() - get coredump size + * @coredump: pointer to &struct coredump_layer + * + * Return: a uint32_t holding the size of the current coredump + */ +uint32_t coredump_layer_get_coredump_size(struct coredump_layer *coredump); + +/** + * coredump_layer_reset_status() - resets coredump status + * @coredump: pointer to &struct coredump_layer + * + * Return: void, + */ +void coredump_layer_reset_status(struct coredump_layer *coredump); + #endif // __HSSPI_COREDUMP_H__ diff --git a/drivers/uwb/qm35/hsspi_log.c b/drivers/uwb/qm35/hsspi_log.c index 45a765567d67..d94cc2554bd4 100644 --- a/drivers/uwb/qm35/hsspi_log.c +++ b/drivers/uwb/qm35/hsspi_log.c @@ -134,6 +134,7 @@ static int parse_log_sources_response(struct log_layer *layer, uint8_t *data, { struct qm35_ctx *qm35_hdl; int idx = 0; + uint16_t current_len = 0; qm35_hdl = container_of(layer, struct qm35_ctx, log_layer); @@ -150,8 +151,15 @@ static int parse_log_sources_response(struct log_layer *layer, uint8_t *data, layer->log_modules[idx].debug = &qm35_hdl->debug; layer->log_modules[idx].id = *data++; layer->log_modules[idx].lvl = *data++; - strcpy(layer->log_modules[idx].name, (char *)data); - data += (strlen((char *)data) + 1); + current_len = strlen((char *)data) + 1; + if (current_len > sizeof(layer->log_modules[idx].name)) { + pr_err("qm35: log module name bigger than allocated buffer: current_len = %d bytes\n", + current_len); + strncpy(layer->log_modules[idx].name, "ERROR", 6); + } else + strncpy(layer->log_modules[idx].name, (char *)data, + current_len); + data += current_len; debug_create_module_entry(&qm35_hdl->debug, &layer->log_modules[idx]); @@ -169,8 +177,6 @@ static int parse_get_log_lvl_response(struct log_layer *layer, uint8_t *data, src_id = *data++; src_lvl = *data; - //qm35_hdl = container_of(layer, struct qm35_ctx, log_layer); - for (idx = 0; idx < layer->log_modules_count; idx++) { if (layer->log_modules[idx].id == src_id) { layer->log_modules[idx].lvl = src_lvl; @@ -240,7 +246,7 @@ static void log_received(struct hsspi_layer *hlayer, struct hsspi_block *blk, switch (hdr.cmd_id) { case LOG_CID_TRACE_NTF: - rb_push(&layer->rb, body, hdr.b_size); + rb_push(&layer->rb, (const char *)body, hdr.b_size); debug_new_trace_available(&qm35_hdl->debug); break; case LOG_CID_SET_LOG_LVL: diff --git a/drivers/uwb/qm35/libfwupdater/src/fwupdater.c b/drivers/uwb/qm35/libfwupdater/src/fwupdater.c index 649319ce3d08..129fe8c7a323 100644 --- a/drivers/uwb/qm35/libfwupdater/src/fwupdater.c +++ b/drivers/uwb/qm35/libfwupdater/src/fwupdater.c @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 +/* + * Copyright 2023 Qorvo US, Inc. + * + */ #ifndef __KERNEL__ #include @@ -12,24 +17,39 @@ /* Extract from C0 rom code */ #define MAX_CERTIFICATE_SIZE 0x400 -#define MAX_CHUNK_SIZE 4096 -#define WAIT_SS_RDY_TIMEOUT 100 +#define MAX_CHUNK_SIZE 3072 +#define WAIT_REBOOT_DELAY_MS 250 +#define WAIT_SS_RDY_CHUNK_TIMEOUT 100 +#define WAIT_SS_RDY_STATUS_TIMEOUT 10 #define RESULT_RETRIES 3 #define RESULT_CMD_INTERVAL_MS 50 +#define CRC_TYPE uint32_t +#define CRC_SIZE (sizeof(CRC_TYPE)) +#define TRANPORT_HEADER_SIZE (sizeof(struct stc) + CRC_SIZE) +#define EMERGENCY_SPI_FREQ 1000000 /* 1MHz */ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #ifndef __KERNEL__ -_Static_assert(sizeof(struct stc) + MAX_CERTIFICATE_SIZE < MAX_CHUNK_SIZE); +_Static_assert(MAX_CHUNK_SIZE >= CRYPTO_IMAGES_CERT_PKG_SIZE); +_Static_assert(TRANPORT_HEADER_SIZE + MAX_CERTIFICATE_SIZE < MAX_CHUNK_SIZE); #endif +/* local stats */ +static int gstats_spi_errors; +static int gstats_ss_rdy_timeouts; + static int send_data_chunks(struct qmrom_handle *handle, char *data, size_t size); +static int check_fw_boot(struct qmrom_handle *handle); int run_fwupdater(struct qmrom_handle *handle, char *fwpkg_bin, size_t size) { int rc; + gstats_spi_errors = 0; + gstats_ss_rdy_timeouts = 0; + if (size < sizeof(struct fw_pkg_hdr_t) + sizeof(struct fw_pkg_img_hdr_t) + CRYPTO_IMAGES_CERT_PKG_SIZE + @@ -52,194 +72,304 @@ static int run_fwupdater_get_status(struct qmrom_handle *handle, struct fw_updater_status_t *status) { uint32_t i = 0; + CRC_TYPE *crc = (CRC_TYPE *)(hstc + 1); bool owa; + memset(hstc, 0, TRANPORT_HEADER_SIZE + sizeof(*status)); while (i++ < RESULT_RETRIES) { // Poll the QM - qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); sstc->all = 0; hstc->all = 0; + *crc = 0; qmrom_spi_transfer(handle->spi_handle, (char *)sstc, - (const char *)hstc, sizeof(hstc)); - // LOG_INFO("Poll received:\n"); - // hexdump(LOG_INFO, sstc, sizeof(sstc)); - /* Line might have been read ready before QM actually handled the previous cmd */ - qmrom_msleep(RESULT_CMD_INTERVAL_MS); - + (const char *)hstc, TRANPORT_HEADER_SIZE); qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); + WAIT_SS_RDY_STATUS_TIMEOUT); sstc->all = 0; hstc->all = 0; hstc->host_flags.pre_read = 1; + *crc = 0; qmrom_spi_transfer(handle->spi_handle, (char *)sstc, - (const char *)hstc, sizeof(hstc)); + (const char *)hstc, TRANPORT_HEADER_SIZE); // LOG_INFO("Pre-Read received:\n"); // hexdump(LOG_INFO, sstc, sizeof(sstc)); /* Stops the loop when QM has a result to share */ owa = sstc->soc_flags.out_waiting; qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); + WAIT_SS_RDY_STATUS_TIMEOUT); sstc->all = 0; hstc->all = 0; hstc->host_flags.read = 1; hstc->len = sizeof(*status); + *crc = 0; qmrom_spi_transfer(handle->spi_handle, (char *)sstc, (const char *)hstc, - sizeof(hstc) + sizeof(*status)); + TRANPORT_HEADER_SIZE + sizeof(*status)); // LOG_INFO("Read received:\n"); - // hexdump(LOG_INFO, sstc, sizeof(hstc) + sizeof(uint32_t)); + // hexdump(LOG_INFO, sstc, sizeof(*hstc) + sizeof(uint32_t)); if (owa) { memcpy(status, sstc->payload, sizeof(*status)); - break; + if (status->magic == FWUPDATER_STATUS_MAGIC) + break; } + qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, + WAIT_SS_RDY_STATUS_TIMEOUT); + // Failed to get the status, reduces the spi speed to + // an emergency speed to maximize the chance to get the + // final status + qmrom_spi_set_freq(EMERGENCY_SPI_FREQ); + gstats_spi_errors++; } - if (!owa) { + if (status->magic != FWUPDATER_STATUS_MAGIC) { LOG_ERR("Timedout waiting for result\n"); return -1; } return 0; } -static struct stc *prepare_hstc(bool copy_data, char *tx, char *data, size_t len) +static CRC_TYPE checksum(const void *data, const size_t size) { - struct stc *hstc = (struct stc *)(copy_data ? tx : data); + CRC_TYPE crc = 0; + CRC_TYPE *ptr = (CRC_TYPE *)data; + CRC_TYPE remainder = size & (CRC_SIZE - 1); + size_t idx; + + for (idx = 0; idx < size; idx += CRC_SIZE, ptr++) + crc += *ptr; + + if (remainder) { + crc += ((uint8_t *)data)[size - 1]; + if (remainder > 1) { + crc += ((uint8_t *)data)[size - 2]; + if (remainder > 2) { + crc += ((uint8_t *)data)[size - 3]; + } + } + } + return crc; +} + +static void prepare_hstc(struct stc *hstc, char *data, size_t len) +{ + CRC_TYPE *crc = (CRC_TYPE *)(hstc + 1); + void *payload = crc + 1; + hstc->all = 0; hstc->host_flags.write = 1; - hstc->len = len; - if (copy_data) - memcpy(hstc->payload, data, len); - return hstc; + hstc->len = len + CRC_SIZE; + *crc = checksum(data, len); +#ifdef CONFIG_INJECT_ERROR + *crc += 2; +#endif + memcpy(payload, data, len); +} + +static int xfer_payload_prep_next(struct qmrom_handle *handle, + const char *step_name, struct stc *hstc, + struct stc *sstc, struct stc *hstc_next, + char **data, size_t *size) +{ + int rc = 0, nb_retry = CONFIG_NB_RETRIES; + CRC_TYPE *crc = (CRC_TYPE *)(hstc + 1); + + do { + int ss_rdy_rc, irq_up; + sstc->all = 0; + rc = qmrom_spi_transfer(handle->spi_handle, (char *)sstc, + (const char *)hstc, + hstc->len + sizeof(struct stc)); + if (hstc_next) { + /* Don't wait idle, prepare the next hstc to be sent */ + size_t to_send = MIN(MAX_CHUNK_SIZE, *size); + prepare_hstc(hstc_next, *data, to_send); + *size -= to_send; + *data += to_send; + hstc_next = NULL; + } + ss_rdy_rc = qmrom_spi_wait_for_ready_line( + handle->ss_rdy_handle, WAIT_SS_RDY_CHUNK_TIMEOUT); + if (ss_rdy_rc) { + LOG_ERR("%s Waiting for ss-rdy failed with %d (nb_retry %d , crc 0x%x)\n", + step_name, ss_rdy_rc, nb_retry, *crc); + gstats_ss_rdy_timeouts++; + rc = -EAGAIN; + } + irq_up = qmrom_spi_read_irq_line(handle->ss_irq_handle); + if ((!rc && !sstc->soc_flags.ready) || irq_up) { + LOG_ERR("%s Retry rc %d, sstc 0x%08x, irq %d, crc %08x\n", + step_name, rc, sstc->all, irq_up, *crc); + rc = -EAGAIN; + gstats_spi_errors++; + } +#ifdef CONFIG_INJECT_ERROR + (*crc)--; +#endif + } while (rc && --nb_retry > 0); + if (rc) { + LOG_ERR("%s transfer failed with %d - (sstc 0x%08x)\n", + step_name, rc, sstc->all); + } + return rc; +} + +static int xfer_payload(struct qmrom_handle *handle, const char *step_name, + struct stc *hstc, struct stc *sstc) +{ + return xfer_payload_prep_next(handle, step_name, hstc, sstc, NULL, NULL, + NULL); } static int send_data_chunks(struct qmrom_handle *handle, char *data, size_t size) { struct fw_updater_status_t status; + struct stc *hstc, *sstc, *hstc_current, *hstc_next; + uint32_t chunk_nr = 0; char *rx, *tx; - struct stc *hstc, *sstc; - size_t to_send; + CRC_TYPE *crc; int rc = 0; - bool copy_data = !qmrom_data_dma_able(data); - qmrom_alloc(rx, MAX_CHUNK_SIZE + sizeof(struct stc)); - qmrom_alloc(tx, MAX_CHUNK_SIZE + sizeof(struct stc)); + LOG_DBG("chunk_nr:%u\n", chunk_nr); + + qmrom_alloc(rx, MAX_CHUNK_SIZE + TRANPORT_HEADER_SIZE); + qmrom_alloc(tx, 2 * (MAX_CHUNK_SIZE + TRANPORT_HEADER_SIZE)); if (!rx || !tx) { LOG_ERR("Rx/Tx buffers allocation failure\n"); - if (rx) - qmrom_free(rx); - if (tx) - qmrom_free(tx); - return -1; + rc = -ENOMEM; + goto exit_nomem; } - hstc = (struct stc *)tx; sstc = (struct stc *)rx; + hstc = (struct stc *)tx; + hstc_current = hstc; + hstc_next = (struct stc *)&tx[MAX_CHUNK_SIZE + TRANPORT_HEADER_SIZE]; + crc = (CRC_TYPE *)(hstc + 1); + + /* wait for the QM to be ready */ + rc = qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, + WAIT_SS_RDY_CHUNK_TIMEOUT); + if (rc) + LOG_ERR("Waiting for ss-rdy failed with %d\n", rc); /* Sending the fw package header */ - LOG_INFO("Sending the fw package header (copy_data is %d)\n", copy_data); - hstc->all = 0; - hstc->host_flags.write = 1; - hstc->len = sizeof(struct fw_pkg_hdr_t); - size -= sizeof(struct fw_pkg_hdr_t); - memcpy(&tx[sizeof(struct stc)], data, sizeof(struct fw_pkg_hdr_t)); - /* Move the data to the next offset minus the stc footprint */ - data += sizeof(struct fw_pkg_hdr_t) - (copy_data ? 0 : sizeof(struct stc)); - qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); - rc = qmrom_spi_transfer(handle->spi_handle, rx, tx, - sizeof(struct fw_pkg_hdr_t) + sizeof(struct stc)); + prepare_hstc(hstc, data, sizeof(struct fw_pkg_hdr_t)); + LOG_INFO("Sending the fw package header (%zu bytes, crc is 0x%08x)\n", + sizeof(struct fw_pkg_hdr_t), *crc); + // hexdump(LOG_INFO, hstc->payload + 4, sizeof(struct fw_pkg_hdr_t)); + rc = xfer_payload(handle, "fw package header", hstc, sstc); if (rc) - { - LOG_ERR("First qmrom_spi_transfer failed with %d\n", rc); - return rc; - } - // hexdump(LOG_INFO, tx + sizeof(struct stc), sizeof(struct fw_pkg_hdr_t)); + goto exit; + /* Move the data to the next offset minus the header footprint */ + size -= sizeof(struct fw_pkg_hdr_t); + data += sizeof(struct fw_pkg_hdr_t); /* Sending the image header */ - LOG_INFO("Sending the image header\n"); - hstc = prepare_hstc(copy_data, tx, data, sizeof(struct fw_pkg_img_hdr_t)); + prepare_hstc(hstc, data, sizeof(struct fw_pkg_img_hdr_t)); + LOG_INFO("Sending the image header (%zu bytes crc 0x%08x)\n", + sizeof(struct fw_pkg_img_hdr_t), *crc); + // hexdump(LOG_INFO, hstc->payload + 4, sizeof(struct fw_pkg_img_hdr_t)); + rc = xfer_payload(handle, "image header", hstc, sstc); + if (rc) + goto exit; size -= sizeof(struct fw_pkg_img_hdr_t); - // hexdump(LOG_INFO, data + sizeof(struct stc), - // sizeof(struct fw_pkg_img_hdr_t)); data += sizeof(struct fw_pkg_img_hdr_t); - qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); - qmrom_spi_transfer(handle->spi_handle, rx, (const char *)hstc, - sizeof(struct fw_pkg_img_hdr_t) + - sizeof(struct stc)); /* Sending the cert chain */ - LOG_INFO("Sending the cert chain\n"); -#if MAX_CHUNK_SIZE < CRYPTO_IMAGES_CERT_PKG_SIZE - hstc = prepare_hstc(true, tx, data, CRYPTO_IMAGES_CERT_KEY_SIZE); - size -= CRYPTO_IMAGES_CERT_KEY_SIZE; - data += CRYPTO_IMAGES_CERT_KEY_SIZE; - qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); - qmrom_spi_transfer(handle->spi_handle, rx, tx, - CRYPTO_IMAGES_CERT_KEY_SIZE); - - hstc = prepare_hstc(true, tx, data, CRYPTO_IMAGES_CERT_KEY_SIZE); - size -= CRYPTO_IMAGES_CERT_KEY_SIZE; - data += CRYPTO_IMAGES_CERT_KEY_SIZE; - qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); - qmrom_spi_transfer(handle->spi_handle, rx, tx, - CRYPTO_IMAGES_CERT_KEY_SIZE); - - hstc = prepare_hstc(true, tx, data, CRYPTO_IMAGES_CERT_CONTENT_SIZE); - size -= CRYPTO_IMAGES_CERT_CONTENT_SIZE; - data += CRYPTO_IMAGES_CERT_CONTENT_SIZE; - qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); - qmrom_spi_transfer(handle->spi_handle, rx, tx, - CRYPTO_IMAGES_CERT_CONTENT_SIZE); -#else - hstc = prepare_hstc(copy_data, tx, data, CRYPTO_IMAGES_CERT_PKG_SIZE); + prepare_hstc(hstc, data, CRYPTO_IMAGES_CERT_PKG_SIZE); + LOG_INFO("Sending the cert chain (%d bytes crc 0x%08x)\n", + CRYPTO_IMAGES_CERT_PKG_SIZE, *crc); + rc = xfer_payload(handle, "cert chain", hstc, sstc); + if (rc) + goto exit; size -= CRYPTO_IMAGES_CERT_PKG_SIZE; - // hexdump(LOG_INFO, data + sizeof(struct stc), 100); data += CRYPTO_IMAGES_CERT_PKG_SIZE; - qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); - qmrom_spi_transfer(handle->spi_handle, rx, (const char *)hstc, - CRYPTO_IMAGES_CERT_PKG_SIZE + sizeof(struct stc)); -#endif /* Sending the fw image */ - LOG_INFO("Sending the image\n"); + LOG_INFO("Sending the image (%zu bytes)\n", size); + LOG_DBG("Sending a chunk (%zu bytes crc 0x%08x)\n", + MIN(MAX_CHUNK_SIZE, size), *crc); + prepare_hstc(hstc_current, data, MIN(MAX_CHUNK_SIZE, size)); + size -= hstc_current->len - CRC_SIZE; + data += hstc_current->len - CRC_SIZE; do { - to_send = MIN(MAX_CHUNK_SIZE, size); - LOG_DBG("Sending a chunk of %zu bytes\n", to_send); - hstc = prepare_hstc(copy_data, tx, data, to_send); - qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); - qmrom_spi_transfer(handle->spi_handle, rx, (const char *)hstc, - to_send + sizeof(struct stc)); - data += to_send; - size -= to_send; + rc = xfer_payload_prep_next(handle, "data chunk", hstc_current, + sstc, hstc_next, &data, &size); + if (rc) + goto exit; + chunk_nr++; + /* swap hstcs */ + hstc = hstc_current; + hstc_current = hstc_next; + hstc_next = hstc; } while (size); - qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, - WAIT_SS_RDY_TIMEOUT); + /* Sends the last now */ + rc = xfer_payload_prep_next(handle, "data chunk", hstc_current, sstc, + NULL, NULL, NULL); +exit: + // tries to get the flashing status anyway... rc = run_fwupdater_get_status(handle, hstc, sstc, &status); - if (rc) { - LOG_ERR("run_fwupdater_get_status returned %d\n", rc); - } else { + if (!rc) { if (status.status) { - LOG_ERR("%s failed, fw updater status %#x (suberror %#x)\n", - __func__, status.status, status.suberror); + LOG_ERR("Flashing failed, fw updater status %#x (errors: sub %#x, crc %u, rram %u, crypto %d)\n", + status.status, status.suberror, + status.crc_errors, status.rram_errors, + status.crypto_errors); rc = status.status; } else { - LOG_INFO("%s succeeded\n", __func__); - } - } + if (gstats_ss_rdy_timeouts + gstats_spi_errors + + status.crc_errors + status.rram_errors + + status.crypto_errors) { + LOG_WARN( + "Flashing succeeded with errors (host %u, ss_rdy_timeout %u, QM %u, crc %u, rram %u, crypto %d)\n", + gstats_spi_errors, + gstats_ss_rdy_timeouts, + status.spi_errors, status.crc_errors, + status.rram_errors, + status.crypto_errors); + } else { + LOG_INFO( + "Flashing succeeded without any errors\n"); + } + if (!handle->skip_check_fw_boot) + rc = check_fw_boot(handle); + } + } else { + LOG_ERR("run_fwupdater_get_status returned %d\n", rc); + } +exit_nomem: if (rx) qmrom_free(rx); if (tx) qmrom_free(tx); return rc; } + +static int check_fw_boot(struct qmrom_handle *handle) +{ + uint8_t raw_flags; + struct stc hstc, sstc; + + handle->dev_ops.reset(handle->reset_handle); + + qmrom_msleep(WAIT_REBOOT_DELAY_MS); + + // Poll the QM + sstc.all = 0; + hstc.all = 0; + while(sstc.all == 0) + qmrom_spi_transfer(handle->spi_handle, (char *)&sstc, + (const char *)&hstc, sizeof(hstc)); + + raw_flags = sstc.raw_flags; + /* The ROM code sends the same quartets for the first byte of each xfers */ + if (((raw_flags & 0xf0) >> 4) == (raw_flags & 0xf)) { + LOG_ERR("%s: firmware not properly started: %#x\n", + __func__, raw_flags); + return -2; + } + return 0; +} diff --git a/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_b0.c b/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_b0.c index 6024dd909324..558a201f82c2 100644 --- a/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_b0.c +++ b/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_b0.c @@ -174,7 +174,7 @@ int qm357xx_rom_b0_probe_device(struct qmrom_handle *handle) if (handle->chip_rev != CHIP_REVISION_B0) { LOG_ERR("%s: wrong chip revision 0x%x\n", __func__, handle->chip_rev); - handle->chip_rev = -1; + handle->chip_rev = CHIP_REVISION_UNKNOWN; return -1; } @@ -378,7 +378,7 @@ static int qm357xx_rom_b0_flash_debug_cert(struct qmrom_handle *handle, WAITING_FOR_DEBUG_CERT_DATA); check_stcs(__func__, __LINE__, handle); qmrom_msleep(SPI_READY_TIMEOUT_MS); - return 0; + return rc; } static int qm357xx_rom_b0_erase_debug_cert(struct qmrom_handle *handle) diff --git a/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_c0.c b/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_c0.c index 2da1f17a60dc..657af2771609 100644 --- a/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_c0.c +++ b/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_c0.c @@ -15,6 +15,11 @@ #define CHIP_VERSION_DEV_REV_PAYLOAD_OFFSET 6 #define CHUNK_SIZE_C0 2040 #define SPI_READY_TIMEOUT_MS_C0 200 +#define SPI_ERROR_DETECTED_DELAY_MS 65 + +#ifndef CONFIG_CHUNK_FLASHING_RETRIES +#define CONFIG_CHUNK_FLASHING_RETRIES 10 +#endif #ifdef C0_WRITE_STATS #include @@ -187,11 +192,11 @@ static int qm357xx_rom_c0_poll_cmd_resp(struct qmrom_handle *handle) } else qm357xx_rom_c0_poll_soc(handle); } while (retries--); - if (retries <= 0) - LOG_ERR("%s failed after %d replies\n", __func__, - handle->comms_retries); - return retries > 0 ? 0 : -1; + LOG_ERR("%s failed after %d replies\n", __func__, + handle->comms_retries); + + return -EPERM; } int qm357xx_rom_c0_probe_device(struct qmrom_handle *handle) @@ -235,7 +240,7 @@ int qm357xx_rom_c0_probe_device(struct qmrom_handle *handle) ((handle->chip_rev != CHIP_REVISION_C2))) { LOG_ERR("%s: wrong chip revision %#x\n", __func__, handle->chip_rev); - handle->chip_rev = -1; + handle->chip_rev = CHIP_REVISION_UNKNOWN; return -1; } @@ -311,7 +316,7 @@ static int qm357xx_rom_c0_flash_data(struct qmrom_handle *handle, struct firmware *fw, uint8_t cmd, uint8_t resp, bool skip_last_check) { - int rc, sent = 0; + int rc, sent = 0, nb_poll_retry, chunk = 0; const char *bin_data = (const char *)fw->data; #ifdef C0_WRITE_STATS ktime_t start_time; @@ -338,6 +343,18 @@ static int qm357xx_rom_c0_flash_data(struct qmrom_handle *handle, break; } qm357xx_rom_c0_poll_soc(handle); + nb_poll_retry = CONFIG_CHUNK_FLASHING_RETRIES; + while (handle->sstc->soc_flags.err && --nb_poll_retry >= 0) { + qmrom_msleep(SPI_ERROR_DETECTED_DELAY_MS); + qm357xx_rom_c0_poll_soc(handle); + LOG_ERR("%s: spi error detected for cmd %#x chunk %d, retry %d, soc_flags 0x%02x\n", + __func__, cmd, chunk, + CONFIG_CHUNK_FLASHING_RETRIES - nb_poll_retry, + handle->sstc->raw_flags); + rc = qm357xx_rom_write_size_cmd32_c0( + handle, cmd, tx_bytes, bin_data - tx_bytes); + qm357xx_rom_c0_poll_soc(handle); + } #ifdef C0_WRITE_STATS if (tx_bytes == CHUNK_SIZE_C0) update_write_max_chunk_stats(start_time); @@ -354,6 +371,7 @@ static int qm357xx_rom_c0_flash_data(struct qmrom_handle *handle, else return SPI_PROTO_WRONG_RESP; } + chunk++; } qmrom_msleep(SPI_READY_TIMEOUT_MS_C0); return 0; @@ -364,10 +382,12 @@ qm357xx_rom_c0_flash_unstitched_fw(struct qmrom_handle *handle, const struct unstitched_firmware *all_fws) { int rc = 0; - uint8_t flash_cmd = handle->qm357xx_soc_info.lcs_state == - CC_BSV_SECURE_LCS ? - ROM_CMD_C0_SEC_LOAD_OEM_IMG_TO_RRAM : - ROM_CMD_C0_SEC_LOAD_ICV_IMG_TO_RRAM; + uint8_t flash_cmd = + handle->qm357xx_soc_info.lcs_state == CC_BSV_SECURE_LCS || + handle->qm357xx_soc_info.lcs_state == + CC_BSV_RMA_LCS ? + ROM_CMD_C0_SEC_LOAD_OEM_IMG_TO_RRAM : + ROM_CMD_C0_SEC_LOAD_ICV_IMG_TO_RRAM; if (all_fws->key1_crt->data[HBK_LOC] == HBK_2E_ICV && handle->qm357xx_soc_info.lcs_state != CC_BSV_CHIP_MANUFACTURE_LCS) { @@ -378,7 +398,8 @@ qm357xx_rom_c0_flash_unstitched_fw(struct qmrom_handle *handle, } if (all_fws->key1_crt->data[HBK_LOC] == HBK_2E_OEM && - handle->qm357xx_soc_info.lcs_state != CC_BSV_SECURE_LCS) { + handle->qm357xx_soc_info.lcs_state != CC_BSV_SECURE_LCS && + handle->qm357xx_soc_info.lcs_state != CC_BSV_RMA_LCS) { LOG_ERR("%s: Trying to flash an OEM fw on a non OEM platform\n", __func__); rc = -EINVAL; @@ -416,6 +437,7 @@ qm357xx_rom_c0_flash_unstitched_fw(struct qmrom_handle *handle, LOG_ERR("%s: Waiting for WAITING_FOR_FIRST_KEY_CERT(%#x) but got %#x\n", __func__, WAITING_FOR_FIRST_KEY_CERT, handle->sstc->payload[0]); + rc = -1; goto end; } @@ -447,6 +469,43 @@ qm357xx_rom_c0_flash_unstitched_fw(struct qmrom_handle *handle, dump_stats(); #endif + if (qmrom_spi_read_irq_line(handle->ss_irq_handle)) { + int retries = handle->comms_retries; + + do { + /* A final product id error likely occured */ + qmrom_pre_read_c0(handle); + qmrom_read_c0(handle); + rc = handle->sstc->payload[0]; + if (rc) { + LOG_ERR("%s: flashing error %d (0x%x) detected\n", + __func__, rc, rc); + break; + } + } while (--retries); + + if (retries <= 0) { + LOG_ERR("%s: flashing error detected but couldn't be fetched\n", + __func__); + rc = -1; + } + } + + /* Flashing is done, the fw should reboot, check we are not still talking to the ROM code */ + if (!rc && !handle->skip_check_fw_boot) { + uint8_t raw_flags; + + qmrom_msleep(SPI_READY_TIMEOUT_MS_C0); + qm357xx_rom_c0_poll_soc(handle); + raw_flags = handle->sstc->raw_flags; + /* The ROM code sends the same quartets for the first byte of each xfers */ + if (((raw_flags & 0xf0) >> 4) == (raw_flags & 0xf)) { + LOG_ERR("%s: firmware not properly started: %#x\n", + __func__, raw_flags); + rc = -2; + } + } + end: qmrom_free(all_fws->fw_img); qmrom_free(all_fws->fw_crt); diff --git a/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_common.c b/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_common.c index e838ebae15cd..05bab45d8e85 100644 --- a/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_common.c +++ b/drivers/uwb/qm35/libqmrom/src/qm357xx_rom_common.c @@ -80,16 +80,16 @@ int qm357xx_rom_probe_device(struct qmrom_handle *handle) { int rc; - /* Test B0 first */ - //rc = qm357xx_rom_b0_probe_device(handle); - //if (!rc) - //return rc; - - /* Test C0 next */ + /* Test C0 first */ rc = qm357xx_rom_c0_probe_device(handle); if (!rc) return rc; + /* Test B0 next */ + rc = qm357xx_rom_b0_probe_device(handle); + if (!rc) + return rc; + /* None matched!!! */ return -1; } @@ -315,22 +315,33 @@ int qm357xx_rom_unpack_fw_macro_pkg(const struct firmware *fw, struct unstitched_firmware *all_fws) { int rc = 0; - uint8_t *p_key1; - uint8_t *p_key2; - uint8_t *p_crt; - uint8_t *p_fw; char *fw_data; uint32_t fw_size; - struct fw_pkg_img_hdr_t *fw_pkg_img_hdr; + struct firmware fw_pkg; rc = qm357xx_rom_fw_macro_pkg_get_fw_idx(fw, 0, &fw_size, &fw_data); if (rc) { LOG_ERR("%s: FW MACRO PACKAGE corupted = %d\n", __func__, rc); - goto err; + return rc; } + fw_pkg.data = (const uint8_t *)fw_data; + fw_pkg.size = fw_size; + return qm357xx_rom_unpack_fw_pkg(&fw_pkg, all_fws); +} + +int qm357xx_rom_unpack_fw_pkg(const struct firmware *fw_pkg, + struct unstitched_firmware *all_fws) +{ + int rc = 0; + uint8_t *p_key1; + uint8_t *p_key2; + uint8_t *p_crt; + uint8_t *p_fw; + struct fw_pkg_img_hdr_t *fw_pkg_img_hdr; + fw_pkg_img_hdr = - (struct fw_pkg_img_hdr_t *)(fw_data + + (struct fw_pkg_img_hdr_t *)(fw_pkg->data + sizeof(struct fw_pkg_hdr_t)); if (fw_pkg_img_hdr->magic != CRYPTO_FIRMWARE_IMAGE_MAGIC_VALUE) { diff --git a/drivers/uwb/qm35/libqmrom/src/qmrom_common.c b/drivers/uwb/qm35/libqmrom/src/qmrom_common.c index 20b241b03bdb..314ba2d6af1c 100644 --- a/drivers/uwb/qm35/libqmrom/src/qmrom_common.c +++ b/drivers/uwb/qm35/libqmrom/src/qmrom_common.c @@ -121,8 +121,9 @@ int qmrom_probe_device(struct qmrom_handle *handle, } struct qmrom_handle *qmrom_init(void *spi_handle, void *reset_handle, - void *ss_rdy_handle, int spi_speed, - int comms_retries, reset_device_fn reset, + void *ss_rdy_handle, void *ss_irq_handle, + int spi_speed, int comms_retries, + reset_device_fn reset, enum device_generation_e dev_gen_hint) { struct qmrom_handle *handle; @@ -144,10 +145,12 @@ struct qmrom_handle *qmrom_init(void *spi_handle, void *reset_handle, handle->spi_handle = spi_handle; handle->reset_handle = reset_handle; handle->ss_rdy_handle = ss_rdy_handle; + handle->ss_irq_handle = ss_irq_handle; handle->comms_retries = comms_retries; handle->chip_rev = CHIP_REVISION_UNKNOWN; handle->device_version = -1; handle->spi_speed = spi_speed; + handle->skip_check_fw_boot = false; handle->dev_ops.reset = reset; diff --git a/drivers/uwb/qm35/qm35-spi.c b/drivers/uwb/qm35/qm35-spi.c index d606e669178d..e8bf1235c930 100644 --- a/drivers/uwb/qm35/qm35-spi.c +++ b/drivers/uwb/qm35/qm35-spi.c @@ -56,12 +56,20 @@ #include "qm35.h" #include "uci_ioctls.h" +#include "qm35_coredump_ioctls.h" #include "hsspi.h" #include "hsspi_uci.h" #include "hsspi_test.h" +#include "hsspi_coredump.h" #define QM35_REGULATOR_DELAY_US 1000 #define QMROM_RETRIES 10 + +#ifndef CONFIG_FLASHING_RETRIES +#define CONFIG_FLASHING_RETRIES 10 /* Intentionally high value */ +#endif + +/* Redefine certificate error here since original definitions are separate */ #define REGULATORS_ENABLED(x) (x->vdd1 || x->vdd2 || x->vdd3 || x->vdd4) #ifndef NO_UWB_HAL @@ -99,6 +107,11 @@ static bool wake_use_csn = false; module_param(wake_use_csn, bool, 0644); MODULE_PARM_DESC(wake_use_csn, "Use HSSPI CSn pin to wake up QM35"); +static bool wake_on_ssirq = true; +module_param(wake_on_ssirq, bool, 0644); +MODULE_PARM_DESC(wake_on_ssirq, + "Allow QM35 to wakeup the platform using ss_irq"); + int trace_spi_xfers; module_param(trace_spi_xfers, int, 0644); MODULE_PARM_DESC(trace_spi_xfers, "Trace all the SPI transfers"); @@ -107,6 +120,10 @@ int qmrom_retries = QMROM_RETRIES; module_param(qmrom_retries, int, 0644); MODULE_PARM_DESC(qmrom_retries, "QMROM retries"); +int flashing_retries = CONFIG_FLASHING_RETRIES; +module_param(flashing_retries, int, 0644); +MODULE_PARM_DESC(flashing_retries, "Flashing retries"); + int reset_on_error = 1; module_param(reset_on_error, int, 0644); MODULE_PARM_DESC(reset_on_error, "Reset the QM35 on successive errors"); @@ -292,7 +309,7 @@ static ssize_t uci_write(struct file *filp, const char __user *buf, size_t len, p->write_done = ∁ - if (copy_from_user(p->data, buf, len)) { + if (copy_from_user(p->data, buf, (u16)len)) { ret = -EFAULT; goto free; } @@ -304,7 +321,7 @@ static ssize_t uci_write(struct file *filp, const char __user *buf, size_t len, wait_for_completion(&comp); - ret = p->status ? p->status : len; + ret = p->status ? p->status : (u16)len; free: uci_packet_free(p); return ret; @@ -335,12 +352,85 @@ static const struct file_operations uci_fops = { .poll = uci_poll, }; +/* + * coredump_ioctl() - ioctl operation for coredump device. + * + */ +static long coredump_ioctl(struct file *filp, unsigned int cmd, + unsigned long args) +{ + void __user *argp = (void __user *)args; + struct miscdevice *dev = filp->private_data; + struct qm35_ctx *qm35_hdl = + container_of(dev, struct qm35_ctx, coredump_dev); + + switch (cmd) { + case QM35_COREDUMP_FORCE: { + return coredump_layer_force_coredump(&qm35_hdl->coredump_layer); + } + case QM35_COREDUMP_GET_SIZE: { + uint32_t size = coredump_layer_get_coredump_size( + &qm35_hdl->coredump_layer); + if (copy_to_user(argp, &size, sizeof(size))) + return -EINVAL; + return 0; + } + default: + dev_err(&qm35_hdl->spi->dev, "unknown ioctl %x to %s device\n", + cmd, qm35_hdl->uci_dev.name); + return -EINVAL; + } +} + +static ssize_t coredump_read(struct file *filp, char __user *buf, size_t len, + loff_t *off) +{ + struct miscdevice *dev = filp->private_data; + struct qm35_ctx *qm35_hdl = + container_of(dev, struct qm35_ctx, coredump_dev); + ssize_t ret = 0; + uint32_t size = + coredump_layer_get_coredump_size(&qm35_hdl->coredump_layer); + uint8_t *cd = coredump_layer_get_coredump(&qm35_hdl->coredump_layer); + + if (IS_ERR(cd)) + return PTR_ERR(cd); + + ret = simple_read_from_buffer(buf, len, off, cd, size); + if (ret == 0 || *off == size) { + /* reset coredump */ + coredump_layer_reset_status(&qm35_hdl->coredump_layer); + } + + return ret; +} + +static __poll_t coredump_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct miscdevice *dev = filp->private_data; + struct qm35_ctx *qm35_ctx = + container_of(dev, struct qm35_ctx, coredump_dev); + __poll_t mask = 0; + + poll_wait(filp, &qm35_ctx->coredump_layer.wq, wait); + + if (coredump_layer_new_coredump_available(&qm35_ctx->coredump_layer)) + mask |= EPOLLIN; + + return mask; +} + +static const struct file_operations coredump_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = coredump_ioctl, + .read = coredump_read, + .poll = coredump_poll, +}; + static irqreturn_t qm35_irq_handler(int irq, void *qm35_ctx) { struct qm35_ctx *qm35_hdl = qm35_ctx; - //printk("qm35 ss-irq handler"); - spin_lock(&qm35_hdl->lock); qm35_hdl->state = QM35_CTRL_STATE_READY; spin_unlock(&qm35_hdl->lock); @@ -362,7 +452,6 @@ static void reenable_ss_irq(struct hsspi *hsspi) static irqreturn_t qm35_ss_rdy_handler(int irq, void *data) { struct qm35_ctx *qm35_hdl = data; - #ifdef CONFIG_QM35_DEBOUNCE_TIME_US static ktime_t old_time; ktime_t current_time; @@ -382,8 +471,13 @@ static irqreturn_t qm35_ss_rdy_handler(int irq, void *data) if (wake_use_wakeup) gpiod_set_value(qm35_hdl->gpio_wakeup, 0); - hsspi_clear_spi_slave_busy(&qm35_hdl->hsspi); - hsspi_set_spi_slave_ready(&qm35_hdl->hsspi); + if (!qm35_hdl->flashing) { + hsspi_clear_spi_slave_busy(&qm35_hdl->hsspi); + hsspi_set_spi_slave_ready(&qm35_hdl->hsspi); + } else { + qm35_hdl->qmrom_qm_ready = true; + wake_up_interruptible(&qm35_hdl->qmrom_wq_ready); + } return IRQ_HANDLED; } @@ -414,55 +508,49 @@ static irqreturn_t qm35_exton_handler(int irq, void *data) struct qm35_ctx *qm35_hdl = data; hsspi_clear_spi_slave_ready(&qm35_hdl->hsspi); + + if (qm35_hdl->hsspi.waiting_ss_rdy) + qm35_wakeup(&qm35_hdl->hsspi); + return IRQ_HANDLED; } void qm35_hsspi_start(struct qm35_ctx *qm35_hdl) { - int irq; - /* nothing to do as HSSPI is already started */ if (qm35_hdl->hsspi.state == HSSPI_RUNNING) return; - irq = gpiod_to_irq(qm35_hdl->gpio_ss_rdy); - if (irq >= 0) { - enable_irq(irq); + enable_irq(qm35_hdl->ss_rdy_irq); #ifdef CONFIG_QM35_RISING_IRQ_NOT_TRIGGERED - /* Some IRQ controller will trigger a rising edge if - * the gpio is high when enabling the IRQ, some will - * not (RPI board for example). In the second case we - * can miss an event depending on if the level rise - * before or after enable_irq. Besides, the handler - * can also run *after* hsspi_start, breaking the - * hsspi thread with a false information. So let's - * sleep and force the SS_READY bit after. - */ + /* Some IRQ controller will trigger a rising edge if + * the gpio is high when enabling the IRQ, some will + * not (RPI board for example). In the second case we + * can miss an event depending on if the level rise + * before or after enable_irq. Besides, the handler + * can also run *after* hsspi_start, breaking the + * hsspi thread with a false information. So let's + * sleep and force the SS_READY bit after. + */ - if (gpiod_get_value(qm35_hdl->gpio_ss_rdy)) - hsspi_set_spi_slave_ready(&qm35_hdl->hsspi); + if (gpiod_get_value(qm35_hdl->gpio_ss_rdy)) + hsspi_set_spi_slave_ready(&qm35_hdl->hsspi); #endif - } hsspi_start(&qm35_hdl->hsspi); } void qm35_hsspi_stop(struct qm35_ctx *qm35_hdl) { - int irq; - /* nothing to do as HSSPI is already stopped */ if (qm35_hdl->hsspi.state == HSSPI_STOPPED) return; hsspi_stop(&qm35_hdl->hsspi); - irq = gpiod_to_irq(qm35_hdl->gpio_ss_rdy); - if (irq >= 0) { - disable_irq_nosync(irq); + disable_irq_nosync(qm35_hdl->ss_rdy_irq); - clear_bit(HSSPI_FLAGS_SS_READY, qm35_hdl->hsspi.flags); - } + clear_bit(HSSPI_FLAGS_SS_READY, qm35_hdl->hsspi.flags); } int qm35_reset_sync(struct qm35_ctx *qm35_hdl) @@ -476,13 +564,105 @@ int qm35_reset_sync(struct qm35_ctx *qm35_hdl) return ret; } + +static int qm_firmware_flash_fw(struct qm35_ctx *qm35_hdl, + struct qmrom_handle *h, + const struct firmware *fw) +{ + int rc = 0, nb_retries = flashing_retries; + do { + /* If the previous flashing failed, re-enter the QM + * rom code so it will be in the same initial state + */ + if (rc) + qmrom_reboot_bootloader(h); + + rc = qm357xx_rom_flash_fw(h, fw); + if (rc) + dev_err(&qm35_hdl->spi->dev, + "Attempt %d: flashing failed with %d!\n", + flashing_retries - nb_retries, rc); + if (rc == PEG_ERR_FIRST_KEY_CERT_OR_FW_VER) + break; + } while (rc && --nb_retries > 0); + return rc; +} + +static int qm_firmware_flash_macro_pkg(struct qm35_ctx *qm35_hdl, + struct qmrom_handle *h, + const struct firmware *fw) +{ + int rc, nb_retries = flashing_retries; + char *fw_data; + uint32_t fw_size; + + rc = qm357xx_rom_fw_macro_pkg_get_fw_idx(fw, 1, &fw_size, &fw_data); + if (rc) { + dev_err(&qm35_hdl->spi->dev, + "FW MACRO PACKAGE corrupted = %d\n", rc); + return rc; + } + if (*(uint32_t *)fw_data != CRYPTO_FIRMWARE_PACK_MAGIC_VALUE) { + rc = -EINVAL; + dev_err(&qm35_hdl->spi->dev, + "FW PACKAGE not found - magic is %04x, size is %d\n", + *(uint32_t *)fw_data, fw_size); + return rc; + } + + do { + /* If the previous flashing failed, re-enter the QM + * rom code so it will be in the same initial state + */ + if (spi_speed_hz) + qmrom_spi_set_freq(spi_speed_hz); + else + qmrom_spi_set_freq(DEFAULT_SPI_CLOCKRATE); + + if (rc) + qmrom_reboot_bootloader(h); + + // The Macro Package contain the fw updater and the package + // simply flash the first and provide the second to + // the updater lib + h->skip_check_fw_boot = true; + rc = qm357xx_rom_flash_fw(h, fw); + h->skip_check_fw_boot = false; + if (rc) { + dev_err(&qm35_hdl->spi->dev, + "Attempt %d: fw updater flashing failed with %d!\n", + flashing_retries - nb_retries, rc); + if (rc == PEG_ERR_FIRST_KEY_CERT_OR_FW_VER) + break; + continue; + } + + // now flash the firmware proper + if (fu_spi_speed_hz) + qmrom_spi_set_freq(fu_spi_speed_hz); + else + qmrom_spi_set_freq(FWUPDATER_SPI_SPEED_HZ); + rc = run_fwupdater(h, fw_data, fw_size); + if (rc) { + dev_err(&qm35_hdl->spi->dev, + "Attempt %d: fw app flashing failed with %d!\n", + flashing_retries - nb_retries, rc); + } + } while (rc && --nb_retries > 0); + return rc; +} + static int qm_firmware_flashing(void *handle, struct qmrom_handle *h, bool *is_macro_pkg, bool use_prod_fw) { struct qm35_ctx *qm35_hdl = (struct qm35_ctx *)handle; struct spi_device *spi = qm35_hdl->spi; + int rc = 0; const struct firmware *fw; - int ret = 0; +#ifdef C0_WRITE_STATS + uint64_t elapsed_time_ns; + ktime_t start_time; +#endif fw = qmrom_spi_get_firmware(&spi->dev, h, is_macro_pkg, use_prod_fw); if (fw == NULL) { @@ -490,59 +670,29 @@ static int qm_firmware_flashing(void *handle, struct qmrom_handle *h, return -1; } - if (!*is_macro_pkg) { - ret = qm357xx_rom_flash_fw(h, fw); - dev_dbg(&spi->dev, "Return qm357xx_rom_flash_fw = %d!\n", ret); - } else { - // The Macro Package contain the fw updater and the package - // simply flash the first and provide the second to - // the updater lib - ret = qm357xx_rom_flash_fw(h, fw); - if (ret) { - dev_err(&spi->dev, - "Firmware updater download failed with %d!\n", - ret); - } else { - // now flash the firmware proper - char *fw_data; - uint32_t fw_size; - ret = qm357xx_rom_fw_macro_pkg_get_fw_idx( - fw, 1, &fw_size, &fw_data); - if (ret) { - dev_err(&spi->dev, - "FW MACRO PACKAGE corupted = %d\n", - ret); - goto error; - } +#ifdef C0_WRITE_STATS + start_time = ktime_get(); +#endif + + qm35_hdl->flashing = true; + if (!*is_macro_pkg) + rc = qm_firmware_flash_fw(qm35_hdl, h, fw); + else + rc = qm_firmware_flash_macro_pkg(qm35_hdl, h, fw); - if (*(uint32_t *)fw_data == - CRYPTO_FIRMWARE_PACK_MAGIC_VALUE) { #ifdef C0_WRITE_STATS - ktime_t start_time = ktime_get(); - uint64_t elapsed_time_ns; + elapsed_time_ns = ktime_to_ns(ktime_sub(ktime_get(), start_time)); + if (!rc) + dev_warn(&spi->dev, "Firmware flashed in %llu us\n", + div_u64(elapsed_time_ns, 1000)); #endif - ret = run_fwupdater(h, fw_data, fw_size); -#ifdef C0_WRITE_STATS - elapsed_time_ns = ktime_to_ns( - ktime_sub(ktime_get(), start_time)); - dev_warn( - &spi->dev, - "Fw_updater flashed - %u bytes in %llu us\n", - fw_size, - div_u64(elapsed_time_ns, 1000)); -#endif - } else { - ret = -EINVAL; - dev_err(&spi->dev, - "FW PACKAGE not found - %04x! fw_size = %d\n", - *(uint32_t *)fw_data, fw_size); - } - } - error: - qmrom_spi_reset_device(qm35_hdl); - } + qmrom_spi_release_firmware(fw); - return ret; + qm35_hdl->flashing = false; + + // reset the device anyway + qmrom_spi_reset_device(qm35_hdl); + return rc; } static int qm_firmware_load(struct qm35_ctx *qm35_hdl) @@ -555,9 +705,11 @@ static int qm_firmware_load(struct qm35_ctx *qm35_hdl) qm35_set_state(qm35_hdl, QM35_CTRL_STATE_FW_DOWNLOADING); - qmrom_set_log_device(&spi->dev, LOG_DBG); + qmrom_set_log_device(&spi->dev, LOG_WARN); - h = qmrom_init(&spi->dev, qm35_hdl, qm35_hdl->gpio_ss_rdy, + enable_irq(qm35_hdl->ss_rdy_irq); + + h = qmrom_init(&spi->dev, qm35_hdl, qm35_hdl, qm35_hdl->gpio_ss_irq, qmrom_spi_speed_hz, qmrom_retries, qmrom_spi_reset_device, DEVICE_GEN_QM357XX); if (!h) { @@ -587,7 +739,7 @@ static int qm_firmware_load(struct qm35_ctx *qm35_hdl) "SoC info not supported on chip revision A0\n"); } - dev_info(&spi->dev, "Starting device flashing!\n"); + dev_dbg(&spi->dev, "Starting device flashing!\n"); ret = qm_firmware_flashing(qm35_hdl, h, &is_macro_pkg, true); if (ret) { qmrom_reboot_bootloader(h); @@ -597,9 +749,11 @@ static int qm_firmware_load(struct qm35_ctx *qm35_hdl) if (ret) dev_err(&spi->dev, "Firmware download failed with %d!\n", ret); else - dev_info(&spi->dev, "Device flashing completed!\n"); + dev_info(&spi->dev, "Device flashing succeeded!\n"); out: + disable_irq_nosync(qm35_hdl->ss_rdy_irq); + qm35_set_state(qm35_hdl, state); return ret; @@ -640,7 +794,6 @@ int qm_get_soc_id(struct qm35_ctx *qm35_hdl, uint8_t *soc_id) static int hsspi_irqs_setup(struct qm35_ctx *qm35_ctx) { int ret, irq; - unsigned long ss_irqflags; /* Get READY GPIO */ qm35_ctx->gpio_ss_rdy = @@ -650,14 +803,15 @@ static int hsspi_irqs_setup(struct qm35_ctx *qm35_ctx) irq = gpiod_to_irq(qm35_ctx->gpio_ss_rdy); if (irq < 0) { - dev_err(&qm35_ctx->spi->dev, "%s: gpiod_to_irq returns %d", - __func__, irq); + dev_err(&qm35_ctx->spi->dev, + "%s: gpiod_to_irq(ss-ready) returns %d", __func__, irq); return irq; } + qm35_ctx->ss_rdy_irq = irq; ret = devm_request_irq(&qm35_ctx->spi->dev, irq, &qm35_ss_rdy_handler, IRQF_TRIGGER_RISING, "hsspi-ss-rdy", qm35_ctx); if (ret) { - dev_err(&qm35_ctx->spi->dev, "%s: devm_request_irq returns %d", + dev_err(&qm35_ctx->spi->dev, "%s: devm_request_irq returned %d", __func__, ret); return ret; } @@ -667,33 +821,44 @@ static int hsspi_irqs_setup(struct qm35_ctx *qm35_ctx) disable_irq(irq); /* get SS_IRQ GPIO */ - qm35_ctx->gpio_ss_irq = devm_gpiod_get_optional(&qm35_ctx->spi->dev, - "ss-irq", GPIOD_IN); + qm35_ctx->gpio_ss_irq = + devm_gpiod_get(&qm35_ctx->spi->dev, "ss-irq", GPIOD_IN); + if (IS_ERR(qm35_ctx->gpio_ss_irq)) { + dev_err(&qm35_ctx->spi->dev, + "%s: gpiod_get_index(ss-irq) returned %pK", __func__, + qm35_ctx->gpio_ss_irq); + } - if (qm35_ctx->gpio_ss_irq) { - if (IS_ERR(qm35_ctx->gpio_ss_irq)) { - dev_err(&qm35_ctx->spi->dev, "error with ss-irq"); - return PTR_ERR(qm35_ctx->gpio_ss_irq); + qm35_ctx->spi->irq = gpiod_to_irq(qm35_ctx->gpio_ss_irq); + if (qm35_ctx->spi->irq < 0) { + dev_err(&qm35_ctx->spi->dev, + "%s: gpiod_to_irq(ss-irq) returned %d", __func__, + qm35_ctx->spi->irq); + return qm35_ctx->spi->irq; + } + ret = devm_request_irq(&qm35_ctx->spi->dev, qm35_ctx->spi->irq, + &qm35_irq_handler, IRQF_TRIGGER_HIGH, + "hsspi-ss-irq", qm35_ctx); + if (ret) { + dev_err(&qm35_ctx->spi->dev, "%s: devm_request_irq returned %d", + __func__, ret); + return ret; + } + + if (wake_on_ssirq) { + ret = enable_irq_wake(qm35_ctx->spi->irq); + if (ret) { + dev_err(&qm35_ctx->spi->dev, + "%s: enable_irq_wake returned %d", __func__, + ret); + return ret; } - - qm35_ctx->spi->irq = gpiod_to_irq(qm35_ctx->gpio_ss_irq); - ss_irqflags = IRQF_TRIGGER_HIGH; - dev_err(&qm35_ctx->spi->dev, "ss-irq ready with gpio"); - } else { - ss_irqflags = irq_get_trigger_type(qm35_ctx->spi->irq); - dev_err(&qm35_ctx->spi->dev, "ss-irq ready with irq-type"); } qm35_ctx->hsspi.odw_cleared = reenable_ss_irq; qm35_ctx->hsspi.wakeup = qm35_wakeup; qm35_ctx->hsspi.reset_qm35 = qm35_reset_hook; - ret = devm_request_irq(&qm35_ctx->spi->dev, qm35_ctx->spi->irq, - &qm35_irq_handler, ss_irqflags, "hsspi-ss-irq", - qm35_ctx); - if (ret) - return ret; - /* Get exton */ qm35_ctx->gpio_exton = devm_gpiod_get_optional(&qm35_ctx->spi->dev, "exton", GPIOD_IN); @@ -701,8 +866,15 @@ static int hsspi_irqs_setup(struct qm35_ctx *qm35_ctx) if (IS_ERR(qm35_ctx->gpio_exton)) return PTR_ERR(qm35_ctx->gpio_exton); - ret = devm_request_irq(&qm35_ctx->spi->dev, - gpiod_to_irq(qm35_ctx->gpio_exton), + irq = gpiod_to_irq(qm35_ctx->gpio_exton); + if (irq < 0) { + dev_err(&qm35_ctx->spi->dev, + "%s: gpiod_to_irq(exton) returned %d", __func__, + irq); + return irq; + } + + ret = devm_request_irq(&qm35_ctx->spi->dev, irq, &qm35_exton_handler, IRQF_TRIGGER_FALLING, "hsspi-exton", qm35_ctx); @@ -832,6 +1004,7 @@ static int qm35_probe(struct spi_device *spi) { struct qm35_ctx *qm35_ctx; struct miscdevice *uci_misc; + struct miscdevice *coredump_misc; struct clk *uwb_clk; int ret = 0; @@ -858,6 +1031,7 @@ static int qm35_probe(struct spi_device *spi) qm35_ctx->spi = spi; qm35_ctx->log_qm_traces = log_qm_traces; spin_lock_init(&qm35_ctx->lock); + init_waitqueue_head(&qm35_ctx->qmrom_wq_ready); spi_set_drvdata(spi, qm35_ctx); @@ -896,6 +1070,12 @@ static int qm35_probe(struct spi_device *spi) uci_misc->fops = &uci_fops; uci_misc->parent = &spi->dev; + coredump_misc = &qm35_ctx->coredump_dev; + coredump_misc->minor = MISC_DYNAMIC_MINOR; + coredump_misc->name = COREDUMP_DEV_NAME; + coredump_misc->fops = &coredump_fops; + coredump_misc->parent = &spi->dev; + /* we need the debugfs root initialized here to be able * to display the soc info populated if flash_on_probe * is set for chips different than A0 @@ -922,9 +1102,7 @@ static int qm35_probe(struct spi_device *spi) if (ret) goto debug_deinit; - ret = coredump_layer_init(&qm35_ctx->coredump_layer, &qm35_ctx->debug); - if (ret) - goto hsspi_test_deinit; + coredump_layer_init(&qm35_ctx->coredump_layer); ret = log_layer_init(&qm35_ctx->log_layer, &qm35_ctx->debug); if (ret) @@ -966,10 +1144,19 @@ static int qm35_probe(struct spi_device *spi) qm35_hsspi_start(qm35_ctx); } + ret = misc_register(&qm35_ctx->coredump_dev); + if (ret) { + dev_err(&spi->dev, "Failed to register coredump device\n"); + goto log_layer_unregister; + } + + dev_info(&spi->dev, "Registered: [%s] misc device\n", + coredump_misc->name); + ret = misc_register(&qm35_ctx->uci_dev); if (ret) { dev_err(&spi->dev, "Failed to register uci device\n"); - goto log_layer_unregister; + goto coredump_misc_deregister; } dev_info(&spi->dev, "Registered: [%s] misc device\n", uci_misc->name); @@ -977,6 +1164,8 @@ static int qm35_probe(struct spi_device *spi) dev_info(&spi->dev, "QM35 spi driver version " DRV_VERSION " probed\n"); return 0; +coredump_misc_deregister: + misc_deregister(&qm35_ctx->coredump_dev); log_layer_unregister: hsspi_unregister(&qm35_ctx->hsspi, &qm35_ctx->log_layer.hlayer); coredump_layer_unregister: @@ -985,7 +1174,6 @@ log_layer_deinit: log_layer_deinit(&qm35_ctx->log_layer); coredump_layer_deinit: coredump_layer_deinit(&qm35_ctx->coredump_layer); -hsspi_test_deinit: hsspi_test_deinit(&qm35_ctx->hsspi); debug_deinit: debug_deinit(&qm35_ctx->debug); @@ -1007,6 +1195,7 @@ static void qm35_remove(struct spi_device *spi) struct qm35_ctx *qm35_hdl = spi_get_drvdata(spi); misc_deregister(&qm35_hdl->uci_dev); + misc_deregister(&qm35_hdl->coredump_dev); qm35_hsspi_stop(qm35_hdl); @@ -1030,10 +1219,36 @@ static void qm35_remove(struct spi_device *spi) #endif } +#ifdef CONFIG_PM_SLEEP +static int qm35_pm_suspend(struct device *dev) +{ + struct qm35_ctx *qm35_hdl = dev_get_drvdata(dev); + + qm35_hsspi_stop(qm35_hdl); + + return 0; +} + +static int qm35_pm_resume(struct device *dev) +{ + struct qm35_ctx *qm35_hdl = dev_get_drvdata(dev); + + qm35_hsspi_start(qm35_hdl); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(qm35_spi_ops, qm35_pm_suspend, qm35_pm_resume); +#if KERNEL_VERSION(5, 17, 0) > LINUX_VERSION_CODE +#define pm_sleep_ptr(_ptr) (IS_ENABLED(CONFIG_PM_SLEEP) ? (_ptr) : NULL) +#endif + static struct spi_driver qm35_spi_driver = { .driver = { .name = "qm35", .of_match_table = of_match_ptr(qm35_dt_ids), + .pm = pm_sleep_ptr(&qm35_spi_ops), }, .probe = qm35_probe, .remove = qm35_remove, diff --git a/drivers/uwb/qm35/qm35.h b/drivers/uwb/qm35/qm35.h index f95c2421ef53..61ef2ba884f4 100644 --- a/drivers/uwb/qm35/qm35.h +++ b/drivers/uwb/qm35/qm35.h @@ -4,18 +4,23 @@ #define __QM35_H___ #include +#include #include #include #include #include #include "uci_ioctls.h" +#include "qm35_coredump_ioctls.h" #include "hsspi.h" #include "hsspi_uci.h" #include "hsspi_coredump.h" #include "hsspi_log.h" #include "debug.h" +#define FWUPDATER_SPI_SPEED_HZ 20000000 +#define DEFAULT_SPI_CLOCKRATE 3000000 + #define DEBUG_CERTIFICATE_SIZE 2560 #define QM_RESET_LOW_MS 2 /* @@ -24,7 +29,7 @@ #define QM_BOOT_MS 450 #define QM_BEFORE_RESET_MS 450 -#define DRV_VERSION "7.1.0-rc2" +#define DRV_VERSION "magenta-7.4.0-rc2" struct regulator; @@ -35,6 +40,7 @@ struct regulator; struct qm35_ctx { unsigned int state; struct miscdevice uci_dev; + struct miscdevice coredump_dev; struct spi_device *spi; struct gpio_desc *gpio_csn; struct gpio_desc *gpio_reset; @@ -42,6 +48,7 @@ struct qm35_ctx { struct gpio_desc *gpio_ss_irq; struct gpio_desc *gpio_exton; struct gpio_desc *gpio_wakeup; + int ss_rdy_irq; spinlock_t lock; bool out_data_wait; bool out_active; @@ -57,6 +64,11 @@ struct qm35_ctx { struct regulator *vdd4; bool regulators_enabled; bool log_qm_traces; + + /* qmrom support */ + struct wait_queue_head qmrom_wq_ready; + bool qmrom_qm_ready; + bool flashing; }; static inline unsigned int qm35_get_state(struct qm35_ctx *qm35_hdl) @@ -78,7 +90,7 @@ static inline int qm35_reset(struct qm35_ctx *qm35_hdl, int timeout_ms) if (qm35_hdl->gpio_reset) { qm35_set_state(qm35_hdl, QM35_CTRL_STATE_RESET); gpiod_set_value(qm35_hdl->gpio_reset, 1); - usleep_range(timeout_ms * 1000, timeout_ms * 1000); + usleep_range(timeout_ms * 1000UL, timeout_ms * 1000UL); gpiod_set_value(qm35_hdl->gpio_reset, 0); qm35_set_state(qm35_hdl, QM35_CTRL_STATE_UNKNOWN); return 0; diff --git a/drivers/uwb/qm35/qm35_coredump_ioctls.h b/drivers/uwb/qm35/qm35_coredump_ioctls.h new file mode 100644 index 000000000000..98f5e5d7c403 --- /dev/null +++ b/drivers/uwb/qm35/qm35_coredump_ioctls.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __QM35_COREDUMP_IOCTLS_H___ +#define __QM35_COREDUMP_IOCTLS_H___ + +#include + +#define COREDUMP_DEV_NAME "qm35-coredump" +#define COREDUMP_IOC_TYPE 'U' + +#define QM35_COREDUMP_FORCE _IO(COREDUMP_IOC_TYPE, 1) +#define QM35_COREDUMP_GET_SIZE _IOR(COREDUMP_IOC_TYPE, 2, unsigned int) + +#endif /* __QM35_COREDUMP_IOCTLS_H___ */ diff --git a/drivers/uwb/qm35/qmrom_spi.c b/drivers/uwb/qm35/qmrom_spi.c index bd04dad85dd4..af631a7542b2 100644 --- a/drivers/uwb/qm35/qmrom_spi.c +++ b/drivers/uwb/qm35/qmrom_spi.c @@ -26,6 +26,7 @@ * QM35 FW ROM protocol SPI ops */ +#include #include #include @@ -51,6 +52,7 @@ void qmrom_set_fwname(const char *name) int qmrom_spi_transfer(void *handle, char *rbuf, const char *wbuf, size_t size) { struct spi_device *spi = (struct spi_device *)handle; + struct qm35_ctx *qm35_ctx = spi_get_drvdata(spi); int rc; struct spi_transfer xfer[] = { @@ -62,6 +64,7 @@ int qmrom_spi_transfer(void *handle, char *rbuf, const char *wbuf, size_t size) }, }; + qm35_ctx->qmrom_qm_ready = false; rc = spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer)); if (trace_spi_xfers) { @@ -174,11 +177,17 @@ void qmrom_spi_release_firmware(const struct firmware *fw) int qmrom_spi_wait_for_ready_line(void *handle, unsigned int timeout_ms) { - int count_down = (int)timeout_ms; - while (!gpiod_get_value(handle) && (--count_down >= 0)) { - udelay(1000); - } - return gpiod_get_value(handle) ? 0 : -1; + struct qm35_ctx *qm35_ctx = (struct qm35_ctx *)handle; + + wait_event_interruptible_timeout(qm35_ctx->qmrom_wq_ready, + qm35_ctx->qmrom_qm_ready, + msecs_to_jiffies(timeout_ms)); + return gpiod_get_value(qm35_ctx->gpio_ss_rdy) > 0 ? 0 : -1; +} + +int qmrom_spi_read_irq_line(void *handle) +{ + return gpiod_get_value(handle); } void qmrom_spi_set_freq(unsigned int freq) diff --git a/drivers/uwb/qm35/uci_ioctls.h b/drivers/uwb/qm35/uci_ioctls.h index f785c5ec9e17..b0adf2fed44f 100644 --- a/drivers/uwb/qm35/uci_ioctls.h +++ b/drivers/uwb/qm35/uci_ioctls.h @@ -14,13 +14,14 @@ #define QM35_CTRL_POWER _IOW(UCI_IOC_TYPE, 4, unsigned int) /* qm35 states */ -enum { QM35_CTRL_STATE_UNKNOWN = 0x0000, - QM35_CTRL_STATE_OFF = 0x0001, - QM35_CTRL_STATE_RESET = 0x0002, - QM35_CTRL_STATE_COREDUMP = 0x0004, - QM35_CTRL_STATE_READY = 0x0008, - QM35_CTRL_STATE_FW_DOWNLOADING = 0x0010, - QM35_CTRL_STATE_UCI_APP = 0x0020, +enum qm35_ctrl_state { + QM35_CTRL_STATE_UNKNOWN = 0x0000, + QM35_CTRL_STATE_OFF = 0x0001, + QM35_CTRL_STATE_RESET = 0x0002, + QM35_CTRL_STATE_COREDUMP = 0x0004, + QM35_CTRL_STATE_READY = 0x0008, + QM35_CTRL_STATE_FW_DOWNLOADING = 0x0010, + QM35_CTRL_STATE_UCI_APP = 0x0020, }; #endif /* __UCI_IOCTLS_H___ */ diff --git a/include/linux/uwb/fwupdater.h b/include/linux/uwb/fwupdater.h index f6849d099d20..ded5b5c74dbf 100644 --- a/include/linux/uwb/fwupdater.h +++ b/include/linux/uwb/fwupdater.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 /* - * Copyright 2021 Qorvo US, Inc. + * Copyright 2023 Qorvo US, Inc. * */ @@ -17,6 +17,12 @@ #include "qmrom.h" #include "qm357xx_fwpkg.h" +#ifndef CONFIG_NB_RETRIES +#define CONFIG_NB_RETRIES 10 +#endif + +// #define CONFIG_INJECT_ERROR 1 + enum fw_pkg_error_e { FW_PKG_SUCESS = 0, FW_PKG_DOWNLOAD_ERROR, @@ -52,10 +58,17 @@ enum fw_pkg_error_e { /*! Firmware Update Status fields */ struct fw_updater_status_t { + uint32_t magic; uint32_t status; uint32_t suberror; + uint32_t spi_errors; + uint32_t crc_errors; + uint32_t rram_errors; + uint32_t crypto_errors; } __attribute__((packed)); +#define FWUPDATER_STATUS_MAGIC 0xCAFECAFE + void run_fwupdater_unit_tests(void *spi_handle); int run_fwupdater(struct qmrom_handle *handle, char *fwpkg_bin, size_t size); diff --git a/include/linux/uwb/qm357xx_rom.h b/include/linux/uwb/qm357xx_rom.h index 03b31bcb833d..163cc457feb2 100644 --- a/include/linux/uwb/qm357xx_rom.h +++ b/include/linux/uwb/qm357xx_rom.h @@ -75,6 +75,8 @@ int qm357xx_rom_fw_macro_pkg_get_fw_idx(const struct firmware *fw, int idx, uint32_t *fw_size, char **fw_fata); int qm357xx_rom_unpack_fw_macro_pkg(const struct firmware *fw, struct unstitched_firmware *all_fws); +int qm357xx_rom_unpack_fw_pkg(const struct firmware *fw_pkg, + struct unstitched_firmware *all_fws); int qm357xx_rom_flash_dbg_cert(struct qmrom_handle *handle, struct firmware *dbg_cert); int qm357xx_rom_erase_dbg_cert(struct qmrom_handle *handle); diff --git a/include/linux/uwb/qmrom.h b/include/linux/uwb/qmrom.h index 6182c427b436..6ef78d8a1de5 100644 --- a/include/linux/uwb/qmrom.h +++ b/include/linux/uwb/qmrom.h @@ -81,6 +81,7 @@ struct qmrom_handle { void *spi_handle; void *reset_handle; void *ss_rdy_handle; + void *ss_irq_handle; int comms_retries; enum device_generation_e dev_gen; enum chip_revision_e chip_rev; @@ -98,11 +99,13 @@ struct qmrom_handle { struct qm358xx_soc_infos qm358xx_soc_info; }; bool is_be; + bool skip_check_fw_boot; }; struct qmrom_handle *qmrom_init(void *spi_handle, void *reset_handle, - void *ss_rdy_handle, int spi_speed, - int comms_retries, reset_device_fn reset, + void *ss_rdy_handle, void *ss_irq_handle, + int spi_speed, int comms_retries, + reset_device_fn reset, enum device_generation_e dev_gen_hint); void qmrom_deinit(struct qmrom_handle *handle); int qmrom_reboot_bootloader(struct qmrom_handle *handle); diff --git a/include/linux/uwb/qmrom_spi.h b/include/linux/uwb/qmrom_spi.h index 0336425e8779..e23d302e78b0 100644 --- a/include/linux/uwb/qmrom_spi.h +++ b/include/linux/uwb/qmrom_spi.h @@ -10,7 +10,7 @@ #ifndef __QMROM_SPI_H__ #define __QMROM_SPI_H__ -#include +#include #include "qmrom_error.h" #include "qmrom.h" @@ -56,6 +56,7 @@ const struct firmware *qmrom_spi_get_firmware_package(void *handle, int lcs_state); void qmrom_spi_release_firmware(const struct firmware *fw); int qmrom_spi_wait_for_ready_line(void *handle, unsigned int timeout_ms); +int qmrom_spi_read_irq_line(void *handle); void qmrom_spi_set_freq(unsigned int freq); unsigned int qmrom_spi_get_freq(void);