summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Peng <robinpeng@google.com>2022-12-15 16:51:56 +0000
committerVictor Liu <victorliu@google.com>2022-12-15 18:14:26 +0000
commit1518c1cda0b86dc3a946c40a51c466000550f842 (patch)
tree746d2b15520acc93079ed42a68320612ea94ea20
parent495a1eadface6ee91cb6fdd1cc644ef14682f7f0 (diff)
downloaduwb-1518c1cda0b86dc3a946c40a51c466000550f842.tar.gz
Revert "Revert "[R-5.2] uwb: update qm35 driver to release R5.2""
This reverts commit 495a1eadface6ee91cb6fdd1cc644ef14682f7f0. Reason for revert: Symptom not exist after re-plug A0 chip. Change-Id: Id31de79fc4a25499d79e4ce60bc1e442f1ed2c69
-rw-r--r--Kbuild6
-rw-r--r--debug.c156
-rw-r--r--debug.h9
-rw-r--r--hsspi_log.c10
-rw-r--r--libqmrom/CMakeLists.txt6
-rw-r--r--libqmrom/include/byteswap.h10
-rw-r--r--libqmrom/include/qmrom.h152
-rw-r--r--libqmrom/include/qmrom_spi.h6
-rw-r--r--libqmrom/include/qmrom_utils.h7
-rw-r--r--libqmrom/include/spi_rom_protocol.h140
-rw-r--r--libqmrom/src/qmrom.c879
-rw-r--r--libqmrom/src/qmrom_a0.c240
-rw-r--r--libqmrom/src/qmrom_b0.c384
-rw-r--r--libqmrom/src/qmrom_c0.c442
-rw-r--r--libqmrom/src/qmrom_common.c421
-rw-r--r--libqmrom/src/spi_rom_protocol.c166
-rw-r--r--qm35-spi.c83
-rw-r--r--qm35.h1
-rw-r--r--qmrom_spi.c28
19 files changed, 1794 insertions, 1352 deletions
diff --git a/Kbuild b/Kbuild
index 94ff5e2..0460278 100644
--- a/Kbuild
+++ b/Kbuild
@@ -6,9 +6,11 @@ qm35-y := \
qm35-spi.o \
qm35_rb.o \
qmrom_spi.o \
- libqmrom/src/qmrom.o \
+ libqmrom/src/qmrom_common.o \
+ libqmrom/src/qmrom_a0.o \
+ libqmrom/src/qmrom_b0.o \
+ libqmrom/src/qmrom_c0.o \
libqmrom/src/qmrom_log.o \
- libqmrom/src/spi_rom_protocol.o \
hsspi.o \
hsspi_uci.o \
hsspi_log.o \
diff --git a/debug.c b/debug.c
index e1213a4..18222a1 100644
--- a/debug.c
+++ b/debug.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
-
/*
* This file is part of the QM35 UCI stack for linux.
*
@@ -268,78 +267,6 @@ static ssize_t debug_coredump_write(struct file *filp, const char __user *buff,
return count;
}
-static int debug_debug_certificate_open(struct inode *inodep, struct file *filep)
-{
- struct debug *debug = priv_from_file(filep);
-
- if (debug->certificate != NULL)
- return -EBUSY;
-
- debug->certificate = kmalloc(sizeof(*debug->certificate) + DEBUG_CERTIFICATE_SIZE,
- GFP_KERNEL);
- if (debug->certificate == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
-static int debug_debug_certificate_close(struct inode *inodep, struct file *filep)
-{
- struct debug *debug = priv_from_file(filep);
- struct qm35_ctx *qm35_hdl;
- int ret;
- const char *operation = filep->f_pos ? "flashing" : "erasing";
-
- qm35_hdl = container_of(debug, struct qm35_ctx, debug);
-
- qm35_hsspi_stop(qm35_hdl);
-
- dev_dbg(&qm35_hdl->spi->dev, "%s debug certificate (%lld bytes)\n", operation,
- filep->f_pos);
-
- if (filep->f_pos) {
-
- debug->certificate->size = filep->f_pos;
-
- } else {
-
- /* WA: qmrom_erase_dbg_cert is not working, waiting to find the root
- * cause, workaround is to write a zeroed certificate
- * ret = qmrom_erase_dbg_cert(qm35_hdl->spi, qmrom_spi_reset_device, qm35_hdl);
- */
- debug->certificate->size = DEBUG_CERTIFICATE_SIZE;
- memset(debug->certificate->data, 0, DEBUG_CERTIFICATE_SIZE);
- }
-
- ret = qmrom_flash_dbg_cert(qm35_hdl->spi, debug->certificate,
- qmrom_spi_reset_device, qm35_hdl);
-
- if (ret)
- dev_err(&qm35_hdl->spi->dev, "%s debug certificate fails: %d\n", operation, ret);
- else
- dev_info(&qm35_hdl->spi->dev, "%s debug certificate success\n", operation);
-
- msleep(QM_BEFORE_RESET_MS);
- qm35_reset(qm35_hdl, QM_RESET_LOW_MS);
- msleep(QM_BOOT_MS);
-
- qm35_hsspi_start(qm35_hdl);
-
- kfree(debug->certificate);
- debug->certificate = NULL;
-
- return 0;
-}
-
-static ssize_t debug_debug_certificate_write(struct file *filp,
- const char __user *buff, size_t count, loff_t *off)
-{
- struct debug *debug = priv_from_file(filp);
-
- return simple_write_to_buffer(debug->certificate->data,
- DEBUG_CERTIFICATE_SIZE, off, buff, count);
-}
-
static const struct file_operations debug_enable_fops = {
.owner = THIS_MODULE,
.write = debug_enable_write,
@@ -372,13 +299,6 @@ static const struct file_operations debug_coredump_fops = {
.write = debug_coredump_write,
};
-static const struct file_operations debug_debug_certificate_fops = {
- .owner = THIS_MODULE,
- .open = debug_debug_certificate_open,
- .write = debug_debug_certificate_write,
- .release = debug_debug_certificate_close,
-};
-
int debug_create_module_entry(struct debug *debug,
struct log_module *log_module)
{
@@ -417,6 +337,21 @@ void debug_new_trace_available(struct debug *debug)
static int debug_devid_show(struct seq_file *s, void *unused)
{
struct debug *debug = (struct debug *)s->private;
+ uint16_t dev_id;
+ int rc;
+
+ if (debug->trace_ops && debug->trace_ops->get_dev_id) {
+ rc = debug->trace_ops->get_dev_id(debug, &dev_id);
+ if (rc < 0)
+ return -EIO;
+ seq_printf(s, "deca%04x\n", dev_id);
+ }
+ return 0;
+}
+
+static int debug_socid_show(struct seq_file *s, void *unused)
+{
+ struct debug *debug = (struct debug *)s->private;
uint8_t soc_id[ROM_SOC_ID_LEN];
int rc;
@@ -430,21 +365,57 @@ static int debug_devid_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(debug_devid);
+DEFINE_SHOW_ATTRIBUTE(debug_socid);
-int debug_init(struct debug *debug, struct dentry *root)
+void debug_soc_info_available(struct debug *debug)
{
struct dentry *file;
- init_waitqueue_head(&debug->wq);
- mutex_init(&debug->pv_filp_lock);
- debug->pv_filp = NULL;
+ debug->chip_dir = debugfs_create_dir("chip", debug->root_dir);
+ if (!debug->chip_dir) {
+ pr_err("qm35: failed to create /sys/kernel/debug/uwb0/chip\n");
+ goto unregister;
+ }
+
+ file = debugfs_create_file("dev_id", 0444, debug->chip_dir, debug,
+ &debug_devid_fops);
+ if (!file) {
+ pr_err("qm35: failed to create /sys/kernel/debug/uwb0/fw/dev_id\n");
+ goto unregister;
+ }
+
+ file = debugfs_create_file("soc_id", 0444, debug->chip_dir, debug,
+ &debug_socid_fops);
+ if (!file) {
+ pr_err("qm35: failed to create /sys/kernel/debug/uwb0/fw/soc_id\n");
+ goto unregister;
+ }
+ return;
+
+unregister:
+ debugfs_remove_recursive(debug->chip_dir);
+}
+
+int debug_init_root(struct debug *debug, struct dentry *root)
+{
debug->root_dir = debugfs_create_dir("uwb0", root);
if (!debug->root_dir) {
pr_err("qm35: failed to create /sys/kernel/debug/uwb0\n");
- goto unregister;
+ return -1;
}
+ return 0;
+}
+
+int debug_init(struct debug *debug)
+{
+ struct dentry *file;
+
+ init_waitqueue_head(&debug->wq);
+ mutex_init(&debug->pv_filp_lock);
+ debug->pv_filp = NULL;
+
debug->fw_dir = debugfs_create_dir("fw", debug->root_dir);
if (!debug->fw_dir) {
pr_err("qm35: failed to create /sys/kernel/debug/uwb0/fw\n");
@@ -472,21 +443,6 @@ int debug_init(struct debug *debug, struct dentry *root)
goto unregister;
}
- file = debugfs_create_file("devid", 0444, debug->fw_dir, debug,
- &debug_devid_fops);
- if (!file) {
- pr_err("qm35: failed to create /sys/kernel/debug/uwb0/fw/devid\n");
- goto unregister;
- }
-
- debug->certificate = NULL;
- file = debugfs_create_file("debug_certificate", 0200, debug->fw_dir, debug,
- &debug_debug_certificate_fops);
- if (!file) {
- pr_err("qm35: failed to create /sys/kernel/debug/uwb0/fw/debug_certificate\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/debug.h b/debug.h
index 2880ce1..6c78cc2 100644
--- a/debug.h
+++ b/debug.h
@@ -46,6 +46,7 @@ struct debug_trace_ops {
rb_entry_size_t (*trace_get_next_size)(struct debug *dbg);
bool (*trace_next_avail)(struct debug *dbg);
void (*trace_reset)(struct debug *dbg);
+ int (*get_dev_id)(struct debug *dbg, uint16_t *dev_id);
int (*get_soc_id)(struct debug *dbg, uint8_t *soc_id);
};
@@ -57,12 +58,13 @@ struct debug_coredump_ops {
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;
- struct binary_chunk *certificate;
+ struct firmware *certificate;
};
// TODO move this from here to a commom place for both log layer and debug
@@ -74,7 +76,8 @@ struct log_module {
struct debug *debug;
};
-int debug_init(struct debug *debug, struct dentry *root);
+int debug_init_root(struct debug *debug, struct dentry *root);
+int debug_init(struct debug *debug);
void debug_deinit(struct debug *debug);
int debug_create_module_entry(struct debug *debug,
@@ -82,4 +85,6 @@ int debug_create_module_entry(struct debug *debug,
void debug_new_trace_available(struct debug *debug);
+void debug_soc_info_available(struct debug *debug);
+
#endif // __DEBUG_H__
diff --git a/hsspi_log.c b/hsspi_log.c
index e9575f7..9a4541d 100644
--- a/hsspi_log.c
+++ b/hsspi_log.c
@@ -404,6 +404,15 @@ static void log_trace_reset(struct debug *dbg)
rb_reset(&qm35_hdl->log_layer.rb);
}
+static int get_dev_id(struct debug *dbg, uint16_t *dev_id)
+{
+ struct qm35_ctx *qm35_hdl;
+
+ qm35_hdl = container_of(dbg, struct qm35_ctx, debug);
+
+ return qm_get_dev_id(qm35_hdl, dev_id);
+}
+
static int get_soc_id(struct debug *dbg, uint8_t *soc_id)
{
struct qm35_ctx *qm35_hdl;
@@ -422,6 +431,7 @@ static const struct debug_trace_ops debug_trace_ops = {
.trace_get_next_size = log_trace_get_next_size,
.trace_next_avail = log_trace_next_avail,
.trace_reset = log_trace_reset,
+ .get_dev_id = get_dev_id,
.get_soc_id = get_soc_id,
};
diff --git a/libqmrom/CMakeLists.txt b/libqmrom/CMakeLists.txt
index 6500a52..3e11781 100644
--- a/libqmrom/CMakeLists.txt
+++ b/libqmrom/CMakeLists.txt
@@ -1,7 +1,9 @@
set(SOURCES
- src/qmrom.c
+ src/qmrom_common.c
+ src/qmrom_a0.c
+ src/qmrom_b0.c
+ src/qmrom_c0.c
src/qmrom_log.c
- src/spi_rom_protocol.c
)
add_library(qmrom SHARED ${SOURCES})
diff --git a/libqmrom/include/byteswap.h b/libqmrom/include/byteswap.h
new file mode 100644
index 0000000..6852736
--- /dev/null
+++ b/libqmrom/include/byteswap.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
+/*
+ * Copyright 2022 Qorvo US, Inc.
+ *
+ */
+
+#ifndef BYTESWAP_H
+#define BYTESWAP_H
+#define bswap_16 __builtin_bswap16
+#endif
diff --git a/libqmrom/include/qmrom.h b/libqmrom/include/qmrom.h
index 8ae60f2..cbc9b28 100644
--- a/libqmrom/include/qmrom.h
+++ b/libqmrom/include/qmrom.h
@@ -1,23 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
/*
* Copyright 2021 Qorvo US, Inc.
*
- * SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
- *
- * This file is provided under the Apache License 2.0, or the
- * GNU General Public License v2.0.
- *
*/
+
#ifndef __QMROM_H__
#define __QMROM_H__
#ifndef __KERNEL__
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
#include <stdint.h>
+#include <stdbool.h>
+#include <byteswap.h>
+#include <inttypes.h>
#else
+#include <linux/kernel.h>
+#include <linux/errno.h>
#include <linux/types.h>
+#include <linux/string.h>
+#define bswap_16 be16_to_cpu
+#define PRIu32 "u"
#endif
#include <qmrom_error.h>
+#undef CHECK_STCS
+
#define PEG_ERR_TIMEOUT PEG_ERR_BASE - 1
#define PEG_ERR_ROM_NOT_READY PEG_ERR_BASE - 2
#define PEG_ERR_SEND_CERT_WRITE PEG_ERR_BASE - 3
@@ -26,11 +36,20 @@
enum chip_revision_e {
CHIP_REVISION_A0 = 0xA0,
CHIP_REVISION_B0 = 0xB0,
+ CHIP_REVISION_C0 = 0xC0,
CHIP_REVISION_UNKNOWN = 0xFF
};
+#define HBK_LOC 12
+typedef enum {
+ HBK_2E_ICV = 0,
+ HBK_2E_OEM = 1,
+ HBK_1E_ICV_OEM = 2,
+} hbk_t;
+
#define ROM_VERSION_A0 0x01a0
#define ROM_VERSION_B0 0xb000
+
#define ROM_SOC_ID_LEN 0x20
#define ROM_UUID_LEN 0x10
@@ -45,38 +64,107 @@ enum chip_revision_e {
/*! Defines the RMA life-cycle state value. */
#define CC_BSV_RMA_LCS 0x7
-/* This function toggles the GPIO driving the RSTn pin of the device
- * It shall be implemented per the user of the library
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+
+struct qmrom_handle;
+
+struct unstitched_firmware {
+ struct firmware *fw_img;
+ struct firmware *fw_crt;
+ struct firmware *key1_crt;
+ struct firmware *key2_crt;
+};
+
+#define SSTC2UINT32(handle, offset) ({\
+ uint32_t tmp = 0xbeefdeed; \
+ if ((handle)->sstc->len >= (offset) + sizeof(tmp)) \
+ memcpy(&tmp, &(handle)->sstc->payload[(offset)], sizeof(tmp)); \
+ tmp; \
+ })
+
+#define SSTC2UINT16(handle, offset) ({\
+ uint16_t tmp = 0xbeed; \
+ if ((handle)->sstc->len >= (offset) + sizeof(tmp)) \
+ memcpy(&tmp, &(handle)->sstc->payload[(offset)], sizeof(tmp)); \
+ tmp; \
+ })
+
+/* Those functions allow the libqmrom to call
+ * revision specific functions
*/
-typedef int (*qmrom_reset_device)(void *reset_handle);
+typedef int (*flash_fw_fn)(struct qmrom_handle *handle,
+ const struct firmware *fw);
+typedef int (*flash_unstitched_fw_fn)(struct qmrom_handle *handle,
+ const struct unstitched_firmware *fw);
+typedef int (*flash_debug_cert_fn)(struct qmrom_handle *handle,
+ struct firmware *dbg_cert);
+typedef int (*erase_debug_cert_fn)(struct qmrom_handle *handle);
-typedef const struct firmware* (*qmrom_get_firmware)(
- void *handle, enum chip_revision_e revision, int lcs_state);
-typedef void (*qmrom_release_firmware)(const struct firmware* fw);
+struct rom_code_ops {
+ flash_fw_fn flash_fw;
+ flash_unstitched_fw_fn flash_unstitched_fw;
+ flash_debug_cert_fn flash_debug_cert;
+ erase_debug_cert_fn erase_debug_cert;
+};
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpedantic"
+/* Those functions allow the libqmrom to call
+ * device specific functions
+ */
+typedef int (*reset_device_fn)(void *handle);
-struct binary_chunk {
- uint32_t size;
- uint8_t data[0];
+
+struct device_ops {
+ reset_device_fn reset;
+};
+
+struct qmrom_handle {
+ void *spi_handle;
+ void *reset_handle;
+ void *ss_rdy_handle;
+ int comms_retries;
+ enum chip_revision_e chip_rev;
+ uint16_t device_version;
+ struct device_ops dev_ops;
+ struct rom_code_ops rom_ops;
+ uint32_t lcs_state;
+ struct stc *hstc;
+ struct stc *sstc;
+ uint8_t soc_id[ROM_SOC_ID_LEN];
+ uint8_t uuid[ROM_UUID_LEN];
+ bool is_be;
};
-int qmrom_download_fw(void *spi_handle,
- qmrom_get_firmware get_fw_fn,
- qmrom_release_firmware release_fw_fn,
- qmrom_reset_device reset_fn,
- void *reset_handle,
- int is_sram,
- int lcs_state);
-int qmrom_erase_dbg_cert(void *spi_handle,
- qmrom_reset_device reset_fn, void *reset_handle);
-int qmrom_flash_dbg_cert(void *spi_handle, struct binary_chunk *dbg_cert,
- qmrom_reset_device reset_fn, void *reset_handle);
-int qmrom_get_soc_info(void *spi_handle,
- qmrom_reset_device reset_fn, void *reset_handle,
- uint8_t soc_id[ROM_SOC_ID_LEN],
- uint8_t uuid[ROM_UUID_LEN],
- uint8_t *lcs_state);
+int qmrom_unstitch_fw(const struct firmware *fw,
+ struct unstitched_firmware *unstitched_fw,
+ enum chip_revision_e revision);
+struct qmrom_handle *qmrom_init(void *spi_handle,
+ void *reset_handle,
+ void *ss_rdy_handle,
+ int comms_retries,
+ reset_device_fn reset);
+void qmrom_deinit(struct qmrom_handle *handle);
+int qmrom_reboot_bootloader(struct qmrom_handle *handle);
+int qmrom_flash_dbg_cert(struct qmrom_handle *handle,
+ struct firmware *dbg_cert);
+int qmrom_erase_dbg_cert(struct qmrom_handle *handle);
+int qmrom_flash_fw(struct qmrom_handle *handle,
+ const struct firmware *fw);
+int qmrom_flash_unstitched_fw(struct qmrom_handle *handle,
+ const struct unstitched_firmware *fw);
+int qmrom_pre_read(struct qmrom_handle *handle);
+int qmrom_read(struct qmrom_handle *handle);
+int qmrom_write_cmd(struct qmrom_handle *handle, uint8_t cmd);
+int qmrom_write_cmd32(struct qmrom_handle *handle, uint32_t cmd);
+int qmrom_write_size_cmd(struct qmrom_handle *handle, uint8_t cmd,
+ uint16_t data_size, const char *data);
+int qmrom_write_size_cmd32(struct qmrom_handle *handle, uint32_t cmd,
+ uint16_t data_size, const char *data);
+
+#ifdef CHECK_STCS
+void check_stcs(const char *func, int line, struct qmrom_handle *h);
+#else
+#define check_stcs(f, l, h)
+#endif
#endif /* __QMROM_H__ */
diff --git a/libqmrom/include/qmrom_spi.h b/libqmrom/include/qmrom_spi.h
index 2266149..42bebb6 100644
--- a/libqmrom/include/qmrom_spi.h
+++ b/libqmrom/include/qmrom_spi.h
@@ -16,15 +16,13 @@
#ifndef __KERNEL__
struct firmware {
- uint32_t size;
- uint8_t data[0];
+ size_t size;
+ const uint8_t *data;
};
#else
#include <linux/firmware.h>
#endif
-#define DEFAULT_SPI_CLOCKRATE_A0 750000
-#define DEFAULT_SPI_CLOCKRATE 3000000
#define DEFAULT_SPI_LATENCY_MS 2
#define SPI_ERR_NOCHAN SPI_ERR_BASE - 1
diff --git a/libqmrom/include/qmrom_utils.h b/libqmrom/include/qmrom_utils.h
index ceb113c..47bdd1f 100644
--- a/libqmrom/include/qmrom_utils.h
+++ b/libqmrom/include/qmrom_utils.h
@@ -11,9 +11,14 @@
#define __QMROM_UTILS_H__
#ifndef __KERNEL__
+#include <stdlib.h>
+#include <stdint.h>
+#ifndef __linux__
+extern void usleep(unsigned int us);
+#else
#include <unistd.h>
-#include <stdlib.h>
+#endif
#define qmrom_msleep(ms) \
do { \
diff --git a/libqmrom/include/spi_rom_protocol.h b/libqmrom/include/spi_rom_protocol.h
index 4881222..f17575e 100644
--- a/libqmrom/include/spi_rom_protocol.h
+++ b/libqmrom/include/spi_rom_protocol.h
@@ -15,7 +15,6 @@
#ifndef __KERNEL__
#include <stdint.h>
-#include <unistd.h>
#else
#include <linux/types.h>
#endif
@@ -41,6 +40,7 @@ struct stc {
uint8_t out_active : 1; // Output active indication: Set to one by the SOC SPI driver to tell the HOST that it is outputting data on MISO line and expecting that the host is doing a read transaction at this time. This is set to zero for all other transactions.
uint8_t out_waiting : 1; // Output data waiting indication: Set to one by the SOC SPI driver to tell the HOST there is data awaiting reading. This is set to zero when there is no data pending output.
} soc_flags;
+ uint8_t raw_flags;
};
uint8_t ul;
uint16_t len;
@@ -63,13 +63,13 @@ struct stc {
#define SPI_DEVICE_READY_FLAGS SPI_SH_ODW_BIT_MASK
/* Communication parameters */
-#define MAX_STC_FRAME_LEN 1024
+#define MAX_STC_FRAME_LEN 2048
#define MAX_STC_PAYLOAD_LEN (MAX_STC_FRAME_LEN - sizeof(struct stc))
#define SPI_NUM_READS_FOR_READY 1
#define SPI_NUM_FAILS_RETRY 4
#define SPI_ET_PROTOCOL 5
#define SPI_RST_LOW_DELAY_MS 20
-#define SPI_INTERCMD_DELAY_MS 10
+#define SPI_INTERCMD_DELAY_MS 1
#define SPI_DEVICE_POLL_RETRY 10
#define SPI_READY_TIMEOUT_MS 50
#define SPI_ET_VERSION_LOCATION 0x601f0000
@@ -89,138 +89,4 @@ struct stc {
#define SPI_ROM_WRITE_IMAGE_SIZE_SIZE 4
#define SPI_ROM_DBG_CERT_SIZE_SIZE 5
-_Static_assert(MAX_STC_PAYLOAD_LEN == 1020,
- "MAX_STC_PAYLOAD_LEN should be 1020...");
-
-enum spi_rsp_e {
- SPI_RSP_WAIT_DOWNLOAD_MODE = 1, /*Waiting for download command*/
- SPI_RSP_WAIT_FOR_KEY1_CERT_A0,
- SPI_RSP_WAIT_FOR_KEY2_CERT_A0,
- SPI_RSP_WAIT_FOR_IMAGE_CERT_A0,
- SPI_RSP_WAIT_IMAGE_SIZE,
- SPI_RSP_WAIT_FOR_IMAGE,
- SPI_RSP_DOWNLOAD_OK,
- SPI_RSP_BOOT_OK,
- SPI_RSP_ERROR_CS, /*Checksum/CRC error*/
- SPI_RSP_ERROR_CERTIFICATE, /*Got error certificate RSA/FW ver/Didn't get all the data before switching to image/...*/
- SPI_RSP_CMD_TOO_SHORT, /*Got command smaller than SPI_HEADER_SIZE. Each command must be at least this size.*/
- SPI_RSP_ERROR_LOADING_IN_DOWNLOAD, /*Error checking certificates or image, going to download mode*/
- SPI_RSP_WAIT_FOR_KEY1_CERT_B0 = 0x11,
- SPI_RSP_WAIT_FOR_KEY2_CERT_B0 = 0x12,
- SPI_RSP_WAIT_FOR_IMAGE_CERT_B0 = 0x13,
- SPI_RSP_WAIT_DBG_CERT_B0 = 0x14,
- SPI_RSP_WAIT_DBG_CERT_SIZE_B0 = 0x1e,
-};
-
-enum spi_cmd_dnld_e {
- SPI_BOOT_DOWNLOAD_RRAM_CMD_A0 = 0x40,
- SPI_BOOT_JUMP_RRAM_CMD,
- SPI_BOOT_DOWNLOAD_SRAM_CMD,
- SPI_BOOT_JUMP_SRAM_CMD,
-
- SPI_BOOT_DOWNLOAD_SEC_ICV_CMD_B0 = 0,
- SPI_BOOT_DOWNLOAD_SEC_OEM_CMD_B0 = 1,
- SPI_BOOT_GET_CHIP_VER_B0 = 2,
- SPI_BOOT_GET_CHIP_INFO_B0 = 3,
- SPI_BOOT_ERASE_DEBUG_CERT_B0 = 4,
- SPI_BOOT_DOWNLOAD_DEBUG_CERT_B0 = 5,
- SPI_BOOT_DOWNLOAD_SEC_IMAGE_DATA_B0 = 0xf,
- SPI_BOOT_DOWNLOAD_CERT_DATA_B0 = 0x10,
- SPI_BOOT_DEBUG_CERT_SIZE_B0 = 0x11,
-};
-
-enum spi_ul_e {
- SPI_UL_NO_PROTOCOL = 0,
- SPI_UL_ROM_BOOT_PROTO = 1,
- SPI_UL_EMB_TEST = 5,
-};
-
-int spi_proto_prepare_write_cmd(void *spi_handle, int do_exp_resp,
- uint8_t exp_resp, int read_len,
- struct stc *sstc, struct stc *hstc,
- enum chip_revision_e revision);
-int spi_proto_send_stc(void *spi_handle, struct stc *sstc,
- const struct stc *hstc, enum chip_revision_e revision);
-int spi_proto_wait_for_device_flag(void *spi_handle, uint8_t flag_mask,
- struct stc *sstc, struct stc *hstc,
- int retries);
-
-#define dump_full_hstc(log_lvl, s, ...) \
- do { \
- log_lvl(__VA_ARGS__); \
- log_lvl(" # host stc: {.rvd 0x%x, .rd %d, .prd %d, .wr %d, .ul 0x%x, .len %u} -- ", \
- s->host_flags.reserved, s->host_flags.read, \
- s->host_flags.pre_read, s->host_flags.write, s->ul, \
- s->len); \
- hexdump(log_lvl, (unsigned char *)s, \
- sizeof(struct stc) + s->len); \
- } while (0)
-
-#define dump_full_sstc(log_lvl, s, ...) \
- do { \
- uint16_t l = s->len; \
- log_lvl(__VA_ARGS__); \
- log_lvl(" # soc stc: {.rvd 0x%x, .err %d, .rdy %d, .oact %d, .owait %d, .ul 0x%x, .len %u} -- ", \
- s->soc_flags.reserved, s->soc_flags.err, \
- s->soc_flags.ready, s->soc_flags.out_active, \
- s->soc_flags.out_waiting, s->ul, l); \
- hexdump(log_lvl, (unsigned char *)s, sizeof(struct stc) + l); \
- } while (0)
-
-#define dump_decoded_hstc(log_lvl, s, ...) \
- do { \
- log_lvl(__VA_ARGS__); \
- log_lvl(" # host stc: {.rvd 0x%x, .rd %d, .prd %d, .wr %d, .ul 0x%x, .len %u}\n", \
- s->host_flags.reserved, s->host_flags.read, \
- s->host_flags.pre_read, s->host_flags.write, s->ul, \
- s->len); \
- } while (0)
-
-#define dump_decoded_sstc(log_lvl, s, ...) \
- do { \
- log_lvl(__VA_ARGS__); \
- log_lvl(" # soc stc: {.rvd 0x%x, .err %d, .rdy %d, .oact %d, .owait %d, .ul 0x%x, .len %u}\n", \
- s->soc_flags.reserved, s->soc_flags.err, \
- s->soc_flags.ready, s->soc_flags.out_active, \
- s->soc_flags.out_waiting, s->ul, s->len); \
- } while (0)
-
-#define dump_raw_hstc(log_lvl, s, ...) \
- do { \
- log_lvl(__VA_ARGS__); \
- log_lvl(" # host stc %d data bytes -- ", s->len); \
- hexdump(log_lvl, (unsigned char *)s, \
- sizeof(struct stc) + s->len); \
- } while (0)
-
-#define dump_raw_sstc(log_lvl, s, ...) \
- do { \
- log_lvl(__VA_ARGS__); \
- log_lvl(" # soc stc %d data bytes -- ", s->len); \
- hexdump(log_lvl, (unsigned char *)s, \
- sizeof(struct stc) + s->len); \
- } while (0)
-
-#define dump_raw_hsstc(log_lvl, h, s, ...) \
- do { \
- log_lvl(__VA_ARGS__); \
- log_lvl("%04x:", (uint32_t)(h->len + sizeof(struct stc))); \
- hexrawdump(log_lvl, (unsigned char *)h, \
- sizeof(struct stc) + h->len); \
- log_lvl(":"); \
- hexrawdump(log_lvl, (unsigned char *)s, \
- sizeof(struct stc) + h->len); \
- log_lvl("\n"); \
- } while (0)
-
-#define dump_raw_buffer(log_lvl, t, r, l, ...) \
- do { \
- log_lvl(__VA_ARGS__); \
- log_lvl("%04x:", l); \
- hexrawdump(log_lvl, t, l); \
- log_lvl(":"); \
- hexrawdump(log_lvl, r, l); \
- log_lvl("\n"); \
- } while (0)
-
#endif /* __SPI_ROM_PROTOCOL_H__ */
diff --git a/libqmrom/src/qmrom.c b/libqmrom/src/qmrom.c
deleted file mode 100644
index c76baae..0000000
--- a/libqmrom/src/qmrom.c
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- * Copyright 2021 Qorvo US, Inc.
- *
- * SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
- *
- * This file is provided under the Apache License 2.0, or the
- * GNU General Public License v2.0.
- *
- */
-#include <qmrom_utils.h>
-#include <qmrom_log.h>
-#include <qmrom_spi.h>
-#include <qmrom.h>
-#include <spi_rom_protocol.h>
-
-#ifndef __KERNEL__
-#include <errno.h>
-#include <stdint.h>
-#include <string.h>
-#else
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#endif
-
-#define CHUNK_SIZE_A0 1016
-#define CHUNK_SIZE_B0 1008
-
-#define HBK_LOC 12
-typedef enum {
- HBK_2E_ICV = 0,
- HBK_2E_OEM = 1,
- HBK_1E_ICV_OEM = 2,
-} hbk_t;
-
-struct unstitched_firmware {
- struct binary_chunk *fw_img;
- struct binary_chunk *fw_crt;
- struct binary_chunk *key1_crt;
- struct binary_chunk *key2_crt;
-};
-
-static int qmrom_chip_revision(void *spi_handle,
- struct stc *sstc,
- struct stc *hstc,
- enum chip_revision_e *revision);
-static int qmrom_unstitch_fw(const struct firmware *fw,
- struct unstitched_firmware *unstitched_fw,
- enum chip_revision_e revision);
-static int qmrom_start_bootloader_download(void *spi_handle, struct stc *sstc,
- struct stc *hstc, int is_sram,
- enum chip_revision_e revision, uint8_t is_oem);
-static int qmrom_get_bootloader_rom_version(void *spi_handle, struct stc *sstc,
- struct stc *hstc, uint16_t *version);
-static int qmrom_send_cert(void *spi_handle, struct binary_chunk *fcert,
- uint16_t exp_read, uint16_t read_size,
- uint16_t cert_size, struct stc *sstc,
- struct stc *hstc, enum chip_revision_e revision);
-static int qmrom_send_image_size(void *spi_handle, struct binary_chunk *fw,
- struct stc *sstc, struct stc *hstc,
- enum chip_revision_e revision);
-static int qmrom_reboot_bootloader(void *spi_handle,
- qmrom_reset_device reset_fn,
- void *reset_handle);
-static int qmrom_send_multichunk_bytes(void *spi_handle,
- struct binary_chunk *fw,
- struct stc *sstc, struct stc *hstc,
- enum chip_revision_e revision,
- int rsp_expected, int cmd_code);
-
-
-static void qmrom_free_stcs(struct stc *hstc, struct stc *sstc)
-{
- if (hstc) qmrom_free(hstc);
- if (sstc) qmrom_free(sstc);
-}
-
-static int qmrom_allocate_stcs(struct stc **hstc, struct stc **sstc)
-{
- int rc = 0;
- uint8_t *tx_buf = NULL, *rx_buf = NULL;
-
- qmrom_alloc(tx_buf, MAX_STC_FRAME_LEN);
- if (tx_buf == NULL) {
- rc = -ENOMEM;
- goto out;
- }
-
- qmrom_alloc(rx_buf, MAX_STC_FRAME_LEN);
- if (rx_buf == NULL) {
- qmrom_free(tx_buf);
- rc = -ENOMEM;
- goto out;
- }
-
- *hstc = (struct stc *)tx_buf;
- *sstc = (struct stc *)rx_buf;
- return rc;
-out:
- qmrom_free_stcs((struct stc *)tx_buf, (struct stc *)rx_buf);
- *hstc = NULL;
- *sstc = NULL;
- return rc;
-}
-
-static int qmrom_send_dbg_cert_size(void *spi_handle, struct binary_chunk *fw,
- struct stc *sstc, struct stc *hstc)
-{
- int rc;
- memset(hstc->payload, 0, SPI_BOOT_DEBUG_CERT_SIZE_B0);
- rc = spi_proto_prepare_write_cmd(spi_handle, 1,
- SPI_RSP_WAIT_DBG_CERT_SIZE_B0,
- SPI_ROM_DBG_CERT_SIZE_SIZE, sstc,
- hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: prepare write failed with %d\n", __func__, rc);
- return rc;
- }
-
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.write = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- hstc->len = sizeof(uint32_t) + 1;
- hstc->payload[0] = SPI_BOOT_DEBUG_CERT_SIZE_B0;
- hstc->payload[1] = fw->size & 0xff;
- hstc->payload[2] = (fw->size >> 8) & 0xff;
- hstc->payload[3] = (fw->size >> 16) & 0xff;
- hstc->payload[4] = (fw->size >> 24) & 0xff;
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- return rc;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "debug_cert_size write\n");
- return 0;
-}
-
-int qmrom_flash_dbg_cert(void *spi_handle, struct binary_chunk *dbg_cert,
- qmrom_reset_device reset_fn, void *reset_handle)
-{
- int rc = 0;
- struct stc *hstc, *sstc;
-
- rc = qmrom_allocate_stcs(&hstc, &sstc);
- if (rc)
- return rc;
-
- LOG_INFO("Rebooting the board\n");
- rc = qmrom_reboot_bootloader(spi_handle, reset_fn, reset_handle);
- if (rc)
- goto out;
-
- rc = spi_proto_prepare_write_cmd(spi_handle, 1,
- 0, SPI_ROM_DBG_CERT_SIZE_SIZE, sstc,
- hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: prepare write failed with %d\n", __func__, rc);
- goto out;
- }
-
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.write = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- hstc->len = 1;
- hstc->payload[0] = SPI_BOOT_DOWNLOAD_DEBUG_CERT_B0;
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- goto out;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "download debug cert\n");
-
- LOG_INFO("Sending the dbg cert size cmd\n");
- rc = qmrom_send_dbg_cert_size(spi_handle, dbg_cert, sstc, hstc);
- if (rc)
- goto out;
-
- rc = qmrom_send_multichunk_bytes(spi_handle, dbg_cert, sstc, hstc, CHIP_REVISION_B0,
- SPI_RSP_WAIT_DBG_CERT_B0, SPI_BOOT_DOWNLOAD_CERT_DATA_B0);
-
-out:
- qmrom_free_stcs(hstc, sstc);
- return rc;
-}
-
-int qmrom_erase_dbg_cert(void *spi_handle,
- qmrom_reset_device reset_fn, void *reset_handle)
-{
- int rc = 0;
- struct stc *hstc, *sstc;
-
- rc = qmrom_allocate_stcs(&hstc, &sstc);
- if (rc)
- return rc;
-
- LOG_INFO("Rebooting the board\n");
- rc = qmrom_reboot_bootloader(spi_handle, reset_fn, reset_handle);
- if (rc)
- goto out;
-
- /* Erasing... */
- hstc->payload[0] = 0;
- rc = spi_proto_prepare_write_cmd(spi_handle, 1,
- 0, 1, sstc, hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: prepare write failed with %d\n", __func__, rc);
- goto out;
- }
- /* Send the erase cmd */
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.write = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- hstc->len = 1;
- hstc->payload[0] = SPI_BOOT_ERASE_DEBUG_CERT_B0;
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- goto out;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "erase debug cert\n");
-
-out:
- qmrom_free_stcs(hstc, sstc);
- return rc;
-}
-
-int qmrom_get_soc_info(void *spi_handle,
- qmrom_reset_device reset_fn, void *reset_handle,
- uint8_t soc_id[ROM_SOC_ID_LEN],
- uint8_t uuid[ROM_UUID_LEN],
- uint8_t *lcs_state)
-{
- int rc = 0;
- struct stc *hstc, *sstc;
- uint8_t *payload;
- int i;
- enum chip_revision_e revision;
-
- rc = qmrom_allocate_stcs(&hstc, &sstc);
- if (rc)
- return rc;
-
- LOG_INFO("Rebooting the board\n");
- rc = qmrom_reboot_bootloader(spi_handle, reset_fn, reset_handle);
- if (rc)
- goto out;
-
- LOG_INFO("Getting the chip revision\n");
- rc = qmrom_chip_revision(spi_handle, sstc, hstc, &revision);
- if (rc)
- goto out;
-
- if (revision == CHIP_REVISION_A0) {
- LOG_WARN("%s: SoC info not supported on chip revision A0\n", __func__);
- rc = -1;
- goto out;
- }
-
- LOG_INFO("Rebooting the board\n");
- rc = qmrom_reboot_bootloader(spi_handle, reset_fn, reset_handle);
- if (rc)
- goto out;
-
- /* Sending command... */
- hstc->payload[0] = 3;
- rc = spi_proto_prepare_write_cmd(spi_handle, 1,
- 0, 1, sstc, hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: prepare write failed with %d\n", __func__, rc);
- goto out;
- }
- /* Send the erase cmd */
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.read = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- hstc->len = 0x32;
- hstc->payload[0] = 0;
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- goto out;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "erase debug cert\n");
-
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.write = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- hstc->len = 1;
- hstc->payload[0] = SPI_BOOT_GET_CHIP_INFO_B0;
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- return rc;
- }
- hstc->all = 0;
- sstc->all = 0;
- memset(hstc->payload, 0, SPI_ROM_READ_INFO_SIZE_B0);
- rc = spi_proto_prepare_write_cmd(spi_handle, 0,
- SPI_RSP_WAIT_DOWNLOAD_MODE,
- SPI_ROM_READ_INFO_SIZE_B0, sstc,
- hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: prepare write failed with %d\n", __func__, rc);
- return rc;
- }
- if (sstc->len != SPI_ROM_READ_INFO_SIZE_B0) {
- LOG_ERR("%s: wrong device info size 0x%x\n", __func__, sstc->len);
- return -1;
- }
-
- /* skip the first byte */
- payload = &sstc->payload[1];
- for (i = 0 ; i < ROM_SOC_ID_LEN ; i++)
- soc_id[i] = payload[ROM_SOC_ID_LEN - i - 1];
- payload += ROM_SOC_ID_LEN;
- *lcs_state = *payload;
- payload += 1;
- for (i = 0 ; i < ROM_UUID_LEN ; i++)
- uuid[i] = payload[ROM_UUID_LEN - i - 1];
-
-out:
- qmrom_free_stcs(hstc, sstc);
- return rc;
-}
-
-int qmrom_download_fw(void *spi_handle,
- qmrom_get_firmware get_fw_fn,
- qmrom_release_firmware release_fw_fn,
- qmrom_reset_device reset_fn,
- void *reset_handle,
- int is_sram,
- int lcs_state)
-{
- int rc = 0;
- struct stc *hstc, *sstc;
- uint16_t spi_rom_read_image_cert_size = 0;
- const struct firmware *stitched_firmware;
- struct unstitched_firmware unstitched_fw = { 0 };
- enum chip_revision_e revision;
- int is_oem;
-
- rc = qmrom_allocate_stcs(&hstc, &sstc);
- if (rc)
- return rc;
-
- LOG_INFO("Rebooting the board\n");
- rc = qmrom_reboot_bootloader(spi_handle, reset_fn, reset_handle);
- if (rc)
- goto fail;
-
- LOG_INFO("Getting the chip revision\n");
- rc = qmrom_chip_revision(spi_handle, sstc, hstc, &revision);
- if (rc)
- goto fail;
-
- if (revision == CHIP_REVISION_A0) {
- spi_rom_read_image_cert_size = SPI_ROM_READ_IMAGE_CERT_SIZE_A0;
- } else if (revision == CHIP_REVISION_B0) {
- spi_rom_read_image_cert_size = SPI_ROM_READ_IMAGE_CERT_SIZE_B0;
- } else {
- LOG_ERR("%s: unknown chip: %d\n", __func__, revision);
- goto fail;
- }
-
-
- stitched_firmware = get_fw_fn(spi_handle, revision, lcs_state);
- if (stitched_firmware == NULL) {
- LOG_ERR("%s: failed getting the binary firmware\n", __func__);
- rc = -1;
- goto fail;
- }
-
- LOG_INFO("Unstitching the fw\n");
- rc = qmrom_unstitch_fw(stitched_firmware, &unstitched_fw, revision);
- if (rc)
- goto fail;
-
- release_fw_fn(stitched_firmware);
-
- is_oem = unstitched_fw.key1_crt->data[HBK_LOC] != HBK_2E_ICV;
- LOG_INFO("Starting the download fw sequence (%s)\n", is_oem ? "OEM" : "ICV");
- rc = qmrom_start_bootloader_download(spi_handle, sstc, hstc,
- is_sram, revision, is_oem);
- if (rc)
- goto fail;
-
- LOG_INFO("Sending the key1 certificate\n");
- rc = qmrom_send_cert(spi_handle, unstitched_fw.key1_crt,
- revision == CHIP_REVISION_A0 ?
- SPI_RSP_WAIT_FOR_KEY1_CERT_A0 :
- SPI_RSP_WAIT_FOR_KEY1_CERT_B0,
- spi_rom_read_image_cert_size,
- unstitched_fw.key1_crt->size,
- sstc, hstc, revision);
- if (rc)
- goto fail;
-
- LOG_INFO("Sending the key2 certificate\n");
- rc = qmrom_send_cert(spi_handle, unstitched_fw.key2_crt,
- revision == CHIP_REVISION_A0 ?
- SPI_RSP_WAIT_FOR_KEY2_CERT_A0 :
- SPI_RSP_WAIT_FOR_KEY2_CERT_B0,
- spi_rom_read_image_cert_size,
- unstitched_fw.key2_crt->size,
- sstc, hstc, revision);
- if (rc)
- goto fail;
-
- LOG_INFO("Sending the content certificate\n");
- rc = qmrom_send_cert(spi_handle, unstitched_fw.fw_crt,
- revision == CHIP_REVISION_A0 ?
- SPI_RSP_WAIT_FOR_IMAGE_CERT_A0 :
- SPI_RSP_WAIT_FOR_IMAGE_CERT_B0,
- spi_rom_read_image_cert_size,
- unstitched_fw.fw_crt->size,
- sstc, hstc, revision);
- if (rc)
- goto fail;
-
- if (revision == CHIP_REVISION_A0) {
- LOG_INFO("Sending the image size\n");
- rc = qmrom_send_image_size(spi_handle, unstitched_fw.fw_img,
- sstc, hstc, revision);
- if (rc)
- goto fail;
- }
-
- LOG_INFO("Sending the image\n");
- rc = qmrom_send_multichunk_bytes(spi_handle, unstitched_fw.fw_img,
- sstc, hstc, revision,
- SPI_RSP_WAIT_FOR_IMAGE,
- SPI_BOOT_DOWNLOAD_SEC_IMAGE_DATA_B0);
- if (rc)
- goto fail;
-
-fail:
- qmrom_free_stcs(hstc, sstc);
- if (unstitched_fw.fw_img) {
- qmrom_free(unstitched_fw.fw_img);
- qmrom_free(unstitched_fw.fw_crt);
- qmrom_free(unstitched_fw.key1_crt);
- qmrom_free(unstitched_fw.key2_crt);
- }
- return rc;
-}
-
-static int qmrom_chip_revision(void *spi_handle,
- struct stc *sstc,
- struct stc *hstc,
- enum chip_revision_e *revision) {
- uint16_t rom_version;
- int rc = 0;
-
- LOG_INFO("Getting the bootloader ROM version\n");
- rc = qmrom_get_bootloader_rom_version(spi_handle, sstc, hstc,
- &rom_version);
- if (rc)
- goto out;
-
- if (rom_version == ROM_VERSION_A0)
- *revision = CHIP_REVISION_A0;
- else if (rom_version == ROM_VERSION_B0)
- *revision = CHIP_REVISION_B0;
- else {
- LOG_ERR("%s: unknown chip revision, received id: 0x%x\n",
- __func__, rom_version);
- *revision = CHIP_REVISION_UNKNOWN;
- rc = 1;
- }
-
- LOG_INFO("detected chip revision: %02x\n", *revision);
-out:
- return rc;
-}
-
-static int qmrom_unstitch_fw(const struct firmware *fw,
- struct unstitched_firmware *unstitched_fw,
- enum chip_revision_e revision) {
- uint32_t tot_len = 0;
- uint32_t fw_img_sz = 0;
- uint32_t fw_crt_sz = 0;
- uint32_t key1_crt_sz = 0;
- uint32_t key2_crt_sz = 0;
- uint8_t *p_key1;
- uint8_t *p_key2;
- uint8_t *p_crt;
- uint8_t *p_fw;
- int ret = 0;
-
- if (revision == CHIP_REVISION_A0) {
- fw_img_sz = fw->size;
- fw_crt_sz = SPI_ROM_WRITE_IMAGE_CERT_SIZE;
- key1_crt_sz = SPI_ROM_WRITE_KEY_CERT_SIZE;
- key2_crt_sz = SPI_ROM_WRITE_KEY_CERT_SIZE;
-
- p_fw = (uint8_t *) fw->data;
- p_key1 = NULL;
- p_key2 = NULL;
- p_crt = NULL;
- tot_len = 0;
- } else if (revision == CHIP_REVISION_B0) {
- // key1
- key1_crt_sz = *(uint32_t * ) & fw->data[tot_len];
- tot_len += sizeof(key1_crt_sz);
- p_key1 = (uint8_t * ) & fw->data[tot_len];
- tot_len += key1_crt_sz;
- if (tot_len >= fw->size) {
- LOG_ERR("%s: Invalid key1_len %u -- stitched len %zu\n",
- __func__, key1_crt_sz, (size_t)fw->size);
- ret = -EINVAL;
- goto out;
- }
-
- // key2
- key2_crt_sz = *(uint32_t * ) & fw->data[tot_len];
- tot_len += sizeof(key2_crt_sz);
- p_key2 = (uint8_t * ) & fw->data[tot_len];
- tot_len += key2_crt_sz;
- if (tot_len >= fw->size) {
- LOG_ERR("%s: Invalid key1_len %u and key2_len %u -- stitched len %zu\n",
- __func__, key1_crt_sz, key2_crt_sz, (size_t)fw->size);
- ret = -EINVAL;
- goto out;
- }
-
- // cert
- fw_crt_sz = *(uint32_t * ) & fw->data[tot_len];
- tot_len += sizeof(fw_crt_sz);
- p_crt = (uint8_t * ) & fw->data[tot_len];
- tot_len += fw_crt_sz;
- if (tot_len >= fw->size) {
- LOG_ERR("%s: Invalid key1_len %u, key2_len %u and content len %u -- stitched len %zu\n",
- __func__, key1_crt_sz, key2_crt_sz, fw_crt_sz,
- (size_t)fw->size);
- ret = -EINVAL;
- goto out;
- }
-
- // fw
- fw_img_sz = *(uint32_t * ) & fw->data[tot_len];
- tot_len += sizeof(fw_img_sz);
- p_fw = (uint8_t * ) & fw->data[tot_len];
- tot_len += fw_img_sz;
- if (tot_len != fw->size) {
- LOG_ERR("%s: Invalid key1_len %u, key2_len %u, content len %u and fw_len %u -- stitched len %zu\n",
- __func__, key1_crt_sz, key2_crt_sz, fw_crt_sz,
- fw_img_sz, (size_t)fw->size);
- ret = -EINVAL;
- goto out;
- }
- } else {
- LOG_ERR("%s: unknown chip: %d\n", __func__, revision);
- goto out;
- }
-
- qmrom_alloc(unstitched_fw->fw_img,
- fw_img_sz + sizeof(unstitched_fw->fw_img));
- if (unstitched_fw->fw_img == NULL) {
- ret = -ENOMEM;
- goto out;
- }
-
- qmrom_alloc(unstitched_fw->fw_crt,
- fw_crt_sz + sizeof(unstitched_fw->fw_crt));
- if (unstitched_fw->fw_crt == NULL) {
- ret = -ENOMEM;
- goto err;
- }
-
- qmrom_alloc(unstitched_fw->key1_crt,
- key1_crt_sz + sizeof(unstitched_fw->key1_crt));
- if (unstitched_fw->key1_crt == NULL) {
- ret = -ENOMEM;
- goto err;
- }
-
- qmrom_alloc(unstitched_fw->key2_crt,
- key2_crt_sz + sizeof(unstitched_fw->key2_crt));
- if (unstitched_fw->key2_crt == NULL) {
- ret = -ENOMEM;
- goto err;
- }
-
- unstitched_fw->key1_crt->size = key1_crt_sz;
- unstitched_fw->key2_crt->size = key2_crt_sz;
- unstitched_fw->fw_crt->size = fw_crt_sz;
- unstitched_fw->fw_img->size = fw_img_sz;
-
- if (revision == CHIP_REVISION_B0) {
- memcpy(unstitched_fw->key1_crt->data, p_key1, key1_crt_sz);
- memcpy(unstitched_fw->key2_crt->data, p_key2, key2_crt_sz);
- memcpy(unstitched_fw->fw_crt->data, p_crt, fw_crt_sz);
- }
-
- memcpy(unstitched_fw->fw_img->data, p_fw, fw_img_sz);
-
- return 0;
-
-err:
- qmrom_free(unstitched_fw->fw_img);
- qmrom_free(unstitched_fw->fw_crt);
- qmrom_free(unstitched_fw->key1_crt);
- qmrom_free(unstitched_fw->key2_crt);
-
-out:
- return ret;
-}
-
-static int qmrom_start_bootloader_download(void *spi_handle, struct stc *sstc,
- struct stc *hstc, int is_sram, enum chip_revision_e revision,
- uint8_t is_oem)
-{
- int rc;
-
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.write = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
-
- if (revision == CHIP_REVISION_A0) {
- hstc->payload[0] = is_sram ? SPI_BOOT_DOWNLOAD_SRAM_CMD :
- SPI_BOOT_DOWNLOAD_RRAM_CMD_A0;
- } else if (revision == CHIP_REVISION_B0) {
- hstc->payload[0] = is_oem ? SPI_BOOT_DOWNLOAD_SEC_OEM_CMD_B0 :
- SPI_BOOT_DOWNLOAD_SEC_ICV_CMD_B0;
- } else {
- LOG_ERR("%s: unknown chip: %d\n", __func__, revision);
- return -1;
- }
-
- hstc->len = 1;
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, revision);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- return rc;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "download write\n");
- return 0;
-}
-
-static int qmrom_get_bootloader_rom_version(void *spi_handle, struct stc *sstc,
- struct stc *hstc, uint16_t *version) {
- int rc;
- uint16_t dev_id = 0;
-
- memset(hstc->payload, 0, SPI_ROM_READ_VERSION_SIZE_A0);
- rc = spi_proto_prepare_write_cmd(spi_handle, 1,
- SPI_RSP_WAIT_DOWNLOAD_MODE,
- SPI_ROM_READ_VERSION_SIZE_A0, sstc,
- hstc, CHIP_REVISION_A0);
- // FIXME: we have to ignore the rc here because for B0, the write cmd
- // function will fail because the SPI_RSP_WAIT_DOWNLOAD_MODE won't match
- // with the expected one as this flag is different between A0 and B0
- // and at this point we don't know the existing revision.
-// if (rc) {
-// LOG_ERR("%s: prepare write failed with %d\n", __func__, rc);
-// return rc;
-// }
-
- *version = sstc->payload[1] << 8 | sstc->payload[2];
- if (*version == ROM_VERSION_A0) {
- LOG_INFO("%s: ROM bootloader version: 0x%04x, Device ID 0x%04x\n",
- __func__, *version, dev_id);
-
- return 0;
- }
-
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.write = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- hstc->len = 1;
- hstc->payload[0] = SPI_BOOT_GET_CHIP_VER_B0;
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- return rc;
- }
- hstc->all = 0;
- sstc->all = 0;
- memset(hstc->payload, 0, SPI_ROM_READ_VERSION_SIZE_B0);
- rc = spi_proto_prepare_write_cmd(spi_handle, 0,
- SPI_RSP_WAIT_DOWNLOAD_MODE,
- SPI_ROM_READ_VERSION_SIZE_B0, sstc,
- hstc, CHIP_REVISION_B0);
- if (rc) {
- LOG_ERR("%s: prepare write failed with %d\n", __func__, rc);
- return rc;
- }
- *version = sstc->payload[1] << 8 | sstc->payload[2];
- dev_id = sstc->payload[3] << 8 | sstc->payload[4];
- LOG_INFO("%s: ROM bootloader version: 0x%04x, Device ID 0x%04x\n", __func__, *version, dev_id);
-
- return 0;
-}
-
-static int qmrom_send_cert(void *spi_handle, struct binary_chunk *fcert,
- uint16_t exp_read, uint16_t read_size,
- uint16_t cert_size, struct stc *sstc,
- struct stc *hstc, enum chip_revision_e revision)
-{
- int rc;
- memset(hstc->payload, 0, read_size);
- rc = spi_proto_prepare_write_cmd(spi_handle, 1, exp_read, read_size,
- sstc, hstc, revision);
- if (rc) {
- LOG_ERR("%s: prepare write failed with %d\n", __func__, rc);
- return rc;
- }
- if (fcert->size < cert_size) {
- LOG_ERR("%s: could not read the full certificate (%d bytes asked, %d read)\n",
- __func__, cert_size, fcert->size);
- return PEG_ERR_SEND_CERT_WRITE;
- }
-
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.write = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
-
- switch (revision) {
- case CHIP_REVISION_A0:
- hstc->len = cert_size;
- memcpy(hstc->payload, fcert->data, cert_size);
- break;
- case CHIP_REVISION_B0:
- hstc->len = cert_size + 1;
- hstc->payload[0] = SPI_BOOT_DOWNLOAD_CERT_DATA_B0;
- memcpy(hstc->payload + 1, fcert->data, cert_size);
- break;
- default:
- LOG_ERR("%s: Wrong revision %d\n", __func__, revision);
- return PEG_ERR_WRONG_REVISION;
- }
-
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, revision);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- return rc;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "certificate write\n");
- return 0;
-}
-
-static int qmrom_send_image_size(void *spi_handle, struct binary_chunk *fw,
- struct stc *sstc, struct stc *hstc, enum chip_revision_e revision)
-{
- int rc;
- uint16_t spi_rom_read_image_size_size = 0;
-
- if (revision == CHIP_REVISION_A0) {
- spi_rom_read_image_size_size = SPI_ROM_READ_IMAGE_SIZE_SIZE_A0;
- } else if (revision == CHIP_REVISION_B0) {
- spi_rom_read_image_size_size = SPI_ROM_READ_IMAGE_SIZE_SIZE_B0;
- } else {
- LOG_ERR("%s: unknown chip: %d\n", __func__, revision);
- return -1;
- }
-
- memset(hstc->payload, 0, spi_rom_read_image_size_size);
- rc = spi_proto_prepare_write_cmd(spi_handle, 1,
- SPI_RSP_WAIT_IMAGE_SIZE,
- spi_rom_read_image_size_size, sstc,
- hstc, revision);
-
- if (rc) {
- LOG_ERR("%s: prepare write failed with %d\n", __func__, rc);
- return rc;
- }
-
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.write = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- hstc->len = sizeof(uint32_t);
- hstc->payload[0] = fw->size & 0xff;
- hstc->payload[1] = (fw->size >> 8) & 0xff;
- hstc->payload[2] = (fw->size >> 16) & 0xff;
- hstc->payload[3] = (fw->size >> 24) & 0xff;
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, revision);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- return rc;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "image_size write\n");
- return 0;
-}
-
-static int qmrom_send_multichunk_bytes(void *spi_handle, struct binary_chunk *fw,
- struct stc *sstc, struct stc *hstc, enum chip_revision_e revision,
- int rsp_expected, int cmd_code)
-{
- size_t total_sent = 0, current_size;
- uint8_t *payload = fw->data;
- uint16_t chunk_size;
-
- if (revision == CHIP_REVISION_A0) {
- chunk_size = CHUNK_SIZE_A0;
- } else if (revision == CHIP_REVISION_B0) {
- chunk_size = CHUNK_SIZE_B0;
- } else {
- LOG_ERR("%s: unknown chip: %d\n", __func__, revision);
- return -1;
- }
-
- do {
- int rc;
- hstc->len = 0;
- hstc->payload[0] = 0;
- rc = spi_proto_prepare_write_cmd(
- spi_handle, 1, rsp_expected, 1, sstc, hstc, revision);
- if (rc) {
- LOG_ERR("%s: spi_proto_prepare_write_cmd failed with %d\n",
- __func__, rc);
- return rc;
- }
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.write = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- current_size = fw->size - total_sent;
- if (current_size > chunk_size)
- current_size = chunk_size;
-
- if (revision == CHIP_REVISION_A0) {
- memcpy(hstc->payload, payload, current_size);
- hstc->len = current_size;
- } else if (revision == CHIP_REVISION_B0) {
- hstc->payload[0] = cmd_code;
- memcpy(&hstc->payload[1], payload, current_size);
- hstc->len = current_size + 1;
- } else {
- LOG_ERR("%s: unknown chip: %d\n", __func__, revision);
- return -1;
- }
-
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, revision);
- if (rc) {
- LOG_ERR("%s: write failed with %d\n", __func__, rc);
- return rc;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "image write\n");
-
- total_sent += current_size;
- payload += current_size;
- } while (total_sent < fw->size);
- return 0;
-}
-
-int qmrom_reboot_bootloader(void *spi_handle,
- qmrom_reset_device reset_fn,
- void *reset_handle)
-{
- int rc;
- rc = qmrom_spi_set_cs_level(spi_handle, 0);
- if (rc) {
- LOG_ERR("%s: spi_set_cs_level(0) failed with %d\n", __func__,
- rc);
- return rc;
- }
- qmrom_msleep(SPI_RST_LOW_DELAY_MS);
-
- reset_fn(reset_handle);
-
- qmrom_msleep(SPI_RST_LOW_DELAY_MS);
-
- rc = qmrom_spi_set_cs_level(spi_handle, 1);
- if (rc) {
- LOG_ERR("%s: spi_set_cs_level(1) failed with %d\n", __func__,
- rc);
- return rc;
- }
- return 0;
-}
diff --git a/libqmrom/src/qmrom_a0.c b/libqmrom/src/qmrom_a0.c
new file mode 100644
index 0000000..aa8bca6
--- /dev/null
+++ b/libqmrom/src/qmrom_a0.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
+/*
+ * Copyright 2022 Qorvo US, Inc.
+ *
+ */
+
+#include <qmrom.h>
+#include <qmrom_spi.h>
+#include <qmrom_log.h>
+#include <qmrom_utils.h>
+#include <spi_rom_protocol.h>
+
+#define DEFAULT_SPI_CLOCKRATE 750000
+#define CHIP_VERSION_CHIP_REV_PAYLOAD_OFFSET 1
+#define CHUNK_SIZE_A0 1016
+
+enum A0_CMD {
+ ROM_CMD_A0_GET_CHIP_VER = 0x0,
+ ROM_CMD_A0_DOWNLOAD_RRAM_CMD = 0x40,
+};
+
+enum A0_RESP {
+ /* Waiting for download command */
+ SPI_RSP_WAIT_DOWNLOAD_MODE = 1,
+ SPI_RSP_WAIT_FOR_KEY1_CERT,
+ SPI_RSP_WAIT_FOR_KEY2_CERT,
+ SPI_RSP_WAIT_FOR_IMAGE_CERT,
+ SPI_RSP_WAIT_IMAGE_SIZE,
+ SPI_RSP_WAIT_FOR_IMAGE,
+ SPI_RSP_DOWNLOAD_OK,
+ SPI_RSP_BOOT_OK,
+ /* Checksum/CRC error */
+ SPI_RSP_ERROR_CS,
+ /* Got error certificate RSA/FW ver. Didn't get
+ * all the data before switching to image...
+ */
+ SPI_RSP_ERROR_CERTIFICATE,
+ /* Got command smaller than SPI_HEADER_SIZE.
+ * Each command must be at least this size.
+ */
+ SPI_RSP_CMD_TOO_SHORT,
+ /* Error checking certificates or image, going
+ * to download mode.
+ */
+ SPI_RSP_ERROR_LOADING_IN_DOWNLOAD,
+};
+
+static int qmrom_a0_flash_fw(struct qmrom_handle *handle,
+ const struct firmware *fw);
+
+void qmrom_a0_poll_soc(struct qmrom_handle *handle)
+{
+ int retries = handle->comms_retries;
+ handle->hstc->all = 0;
+ qmrom_msleep(SPI_READY_TIMEOUT_MS);
+ do {
+ qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ 1);
+ } while (retries-- && handle->sstc->raw_flags == 0);
+}
+
+int qmrom_a0_wait_ready(struct qmrom_handle *handle)
+{
+ int retries = handle->comms_retries;
+ qmrom_a0_poll_soc(handle);
+
+ while (retries-- &&
+ !handle->sstc->soc_flags.out_waiting)
+ {
+ qmrom_a0_poll_soc(handle);
+ }
+
+ return retries > 0 ? 0 : -1;
+}
+
+int qmrom_a0_probe_device(struct qmrom_handle *handle)
+{
+ int rc;
+ LOG_DBG("%s: enters...\n", __func__);
+ handle->is_be = true;
+
+ qmrom_spi_set_freq(DEFAULT_SPI_CLOCKRATE);
+
+ rc = qmrom_reboot_bootloader(handle);
+ if (rc) {
+ LOG_ERR("%s: cannot reset the device...\n", __func__);
+ return rc;
+ }
+
+ rc = qmrom_a0_wait_ready(handle);
+ if (rc) {
+ LOG_INFO("%s: maybe not a A0 device\n", __func__);
+ return rc;
+ }
+ qmrom_pre_read(handle);
+ handle->sstc->len = bswap_16(handle->sstc->len);
+ if (handle->sstc->len > 0xff) {
+ /* likely the wrong endianness, B0 or C0? */
+ return -1;
+ }
+ qmrom_read(handle);
+
+ LOG_DBG("%s: Set the chip_rev/device_version\n", __func__);
+ handle->chip_rev = bswap_16(SSTC2UINT16(handle,
+ CHIP_VERSION_CHIP_REV_PAYLOAD_OFFSET)) & 0xFF;
+
+ if (handle->chip_rev != CHIP_REVISION_A0) {
+ LOG_ERR("%s: wrong chip revision %#x\n", __func__, handle->chip_rev);
+ handle->chip_rev = -1;
+ return -1;
+ }
+
+ /* Set rom ops */
+ handle->rom_ops.flash_fw = qmrom_a0_flash_fw;
+ handle->rom_ops.flash_debug_cert = NULL;
+ handle->rom_ops.erase_debug_cert = NULL;
+ return 0;
+}
+
+int qmrom_a0_write_data(struct qmrom_handle *handle,
+ uint16_t data_size, const char *data)
+{
+ handle->hstc->all = 0;
+ handle->hstc->host_flags.write = 1;
+ handle->hstc->ul = 1;
+ handle->hstc->len = data_size;
+ memcpy(handle->hstc->payload, data, data_size);
+
+ return qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ sizeof(struct stc) + data_size);
+}
+
+static int qmrom_a0_write_chunks(struct qmrom_handle *handle,
+ const struct firmware *fw)
+{
+ int rc, sent = 0;
+ const char *bin_data = (const char *)fw->data;
+
+ check_stcs(__func__, __LINE__, handle);
+ while (sent < fw->size) {
+ uint32_t tx_bytes = fw->size - sent;
+ if (tx_bytes > CHUNK_SIZE_A0) tx_bytes = CHUNK_SIZE_A0;
+
+ LOG_DBG("%s: poll soc...\n", __func__);
+ check_stcs(__func__, __LINE__, handle);
+ qmrom_a0_poll_soc(handle);
+ qmrom_pre_read(handle);
+ handle->sstc->len = bswap_16(handle->sstc->len);
+ qmrom_read(handle);
+ if (handle->sstc->payload[0] != SPI_RSP_WAIT_FOR_IMAGE)
+ {
+ LOG_ERR("%s: wrong data result (%#x vs %#x)!!!\n",
+ __func__, handle->sstc->payload[0] & 0xff,
+ SPI_RSP_WAIT_FOR_IMAGE);
+ return SPI_PROTO_WRONG_RESP;
+ }
+
+ LOG_DBG("%s: sending %"PRIu32" bytes of data\n", __func__, tx_bytes);
+ rc = qmrom_a0_write_data(handle, tx_bytes, bin_data);
+ if (rc)
+ return rc;
+ sent += tx_bytes;
+ bin_data += tx_bytes;
+ check_stcs(__func__, __LINE__, handle);
+ }
+ return 0;
+}
+
+static int qmrom_a0_flash_fw(struct qmrom_handle *handle,
+ const struct firmware *fw)
+{
+ int rc = 0, resp;
+
+ LOG_DBG("%s: starting...\n", __func__);
+
+ /* Reboot since the rom code on A0 seems
+ * to have issues when starting flashing
+ * after some prior interaction (like GET_CHIP_VERSION)
+ */
+ rc = qmrom_reboot_bootloader(handle);
+ if (rc) {
+ LOG_ERR("%s: cannot reset the device...\n", __func__);
+ return rc;
+ }
+
+ rc = qmrom_a0_wait_ready(handle);
+ if (rc) {
+ LOG_ERR("%s: timedout waiting for the device to be ready\n", __func__);
+ return rc;
+ }
+ qmrom_pre_read(handle);
+ handle->sstc->len = bswap_16(handle->sstc->len);
+ qmrom_read(handle);
+ if (handle->sstc->payload[0] != SPI_RSP_WAIT_DOWNLOAD_MODE)
+ {
+ LOG_ERR("%s: wrong data result (%#x vs %#x)!!!\n",
+ __func__, handle->sstc->payload[0] & 0xff,
+ SPI_RSP_WAIT_DOWNLOAD_MODE);
+ return SPI_PROTO_WRONG_RESP;
+ }
+
+ check_stcs(__func__, __LINE__, handle);
+ LOG_DBG("%s: sending ROM_CMD_A0_DOWNLOAD_RRAM_CMD command\n", __func__);
+ rc = qmrom_write_cmd(handle, ROM_CMD_A0_DOWNLOAD_RRAM_CMD);
+ if (rc)
+ return rc;
+
+ for (resp = SPI_RSP_WAIT_FOR_KEY1_CERT ; resp < SPI_RSP_WAIT_FOR_IMAGE ; resp++)
+ {
+ qmrom_a0_poll_soc(handle);
+ qmrom_pre_read(handle);
+ handle->sstc->len = bswap_16(handle->sstc->len);
+ qmrom_read(handle);
+ if (handle->sstc->payload[0] != resp)
+ {
+ LOG_ERR("%s: wrong data result (%#x vs %#x)!!!\n",
+ __func__, handle->sstc->payload[0] & 0xff,
+ resp);
+ return SPI_PROTO_WRONG_RESP;
+ }
+ if (resp < SPI_RSP_WAIT_IMAGE_SIZE) {
+ rc = qmrom_write_cmd(handle, 0);
+ if (rc)
+ return rc;
+ }
+ }
+
+ LOG_DBG("%s: sending fw size\n", __func__);
+ rc = qmrom_a0_write_data(handle, sizeof(uint32_t),
+ (const char *)&fw->size);
+ if (rc)
+ return rc;
+
+ check_stcs(__func__, __LINE__, handle);
+ rc = qmrom_a0_write_chunks(handle, fw);
+ check_stcs(__func__, __LINE__, handle);
+ return rc;
+}
diff --git a/libqmrom/src/qmrom_b0.c b/libqmrom/src/qmrom_b0.c
new file mode 100644
index 0000000..0dc3921
--- /dev/null
+++ b/libqmrom/src/qmrom_b0.c
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
+/*
+ * Copyright 2022 Qorvo US, Inc.
+ *
+ */
+
+#include <qmrom.h>
+#include <qmrom_spi.h>
+#include <qmrom_log.h>
+#include <qmrom_utils.h>
+#include <spi_rom_protocol.h>
+
+#define DEFAULT_SPI_CLOCKRATE 3000000
+#define CHIP_VERSION_CHIP_REV_PAYLOAD_OFFSET 1
+#define CHIP_VERSION_DEV_REV_PAYLOAD_OFFSET 3
+#define CHUNK_SIZE_B0 1008
+
+enum B0_CMD {
+ ROM_CMD_B0_SEC_LOAD_ICV_IMG_TO_RRAM = 0x0,
+ ROM_CMD_B0_SEC_LOAD_OEM_IMG_TO_RRAM = 0x1,
+ ROM_CMD_B0_GET_CHIP_VER = 0x2,
+ ROM_CMD_B0_GET_SOC_INFO = 0x3,
+ ROM_CMD_B0_ERASE_DBG_CERT = 0x4,
+ ROM_CMD_B0_WRITE_DBG_CERT = 0x5,
+ ROM_CMD_B0_SEC_IMAGE_DATA = 0xf,
+ ROM_CMD_B0_CERT_DATA = 0x10,
+ ROM_CMD_B0_DEBUG_CERT_SIZE = 0x11,
+};
+
+enum B0_RESP {
+ READY_FOR_CS_LOW_CMD = 0x00,
+ WRONG_CS_LOW_CMD = 0x01,
+ WAITING_FOR_NS_RRAM_FILE_SIZE = 0x02,
+ WAITING_FOR_NS_SRAM_FILE_SIZE = 0x03,
+ WAITING_FOR_NS_RRAM_FILE_DATA = 0x04,
+ WAITING_FOR_NS_SRAM_FILE_DATA = 0x05,
+ WAITING_FOR_SEC_FILE_DATA = 0x06,
+ ERR_NS_SRAM_OR_RRAM_SIZE_CMD = 0x07,
+ ERR_SEC_RRAM_SIZE_CMD = 0x08,
+ ERR_WAITING_FOR_NS_IMAGE_DATA_CMD = 0x09,
+ ERR_WAITING_FOR_SEC_IMAGE_DATA_CMD = 0x0A,
+ ERR_IMAGE_SIZE_IS_ZERO = 0x0B,
+ /* Got more data than expected size */
+ ERR_IMAGE_SIZE_TOO_BIG = 0x0C,
+ /* Image must divide in 16 without remainder */
+ ERR_IMAGE_IS_NOT_16BYTES_MUL = 0x0D,
+ ERR_GOT_DATA_MORE_THAN_ALLOWED = 0x0E,
+ /* Remainder is allowed only for last packet */
+ ERR_RRAM_DATA_REMAINDER_NOT_ALLOWED = 0x0F,
+ ERR_WAITING_FOR_CERT_DATA_CMD = 0x10,
+ WAITING_FOR_FIRST_KEY_CERT = 0x11,
+ WAITING_FOR_SECOND_KEY_CERT = 0x12,
+ WAITING_FOR_CONTENT_CERT = 0x13,
+ WAITING_FOR_DEBUG_CERT_DATA = 0x14,
+ ERR_FIRST_KEY_CERT_OR_FW_VER = 0x15,
+ ERR_SECOND_KEY_CERT = 0x16,
+ ERR_CONTENT_CERT_DOWNLOAD_ADDR = 0x17,
+ /* If the content certificate contains to much images */
+ ERR_TOO_MANY_IMAGES_IN_CONTENT_CERT = 0x18,
+ ERR_ADDRESS_NOT_DIVIDED_BY_8 = 0x19,
+ ERR_IMAGE_BOUNDARIES = 0x1A,
+ /* Expected ICV type and got OEM */
+ ERR_CERT_TYPE = 0x1B,
+ ERR_PRODUCT_ID = 0x1C,
+ ERR_RRAM_RANGE_OR_WRITE = 0x1D,
+ WAITING_TO_DEBUG_CERTIFICATE_SIZE = 0x1E,
+ ERR_DEBUG_CERT_SIZE = 0x1F,
+};
+
+static int qmrom_b0_flash_fw(struct qmrom_handle *handle,
+ const struct firmware *fw);
+static int qmrom_b0_flash_debug_cert(struct qmrom_handle *handle,
+ struct firmware *dbg_cert);
+static int qmrom_b0_erase_debug_cert(struct qmrom_handle *handle);
+static int qmrom_b0_flash_unstitched_fw(struct qmrom_handle *handle,
+ const struct unstitched_firmware *all_fws);
+
+static void qmrom_b0_poll_soc(struct qmrom_handle *handle)
+{
+ int retries = handle->comms_retries;
+ memset(handle->hstc, 0, sizeof(struct stc));
+ qmrom_msleep(SPI_READY_TIMEOUT_MS);
+ do {
+ qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ sizeof(struct stc) + handle->hstc->len);
+ } while (retries-- && handle->sstc->raw_flags == 0);
+}
+
+static int qmrom_b0_wait_ready(struct qmrom_handle *handle)
+{
+ int retries = handle->comms_retries;
+ qmrom_b0_poll_soc(handle);
+
+ /* handle->sstc has been updated */
+ while (retries-- &&
+ handle->sstc->raw_flags != SPI_SH_READY_CMD_BIT_MASK)
+ {
+ if (handle->sstc->soc_flags.out_waiting) {
+ qmrom_pre_read(handle);
+ } else if (handle->sstc->soc_flags.out_active) {
+ if (handle->sstc->len > 0xff) {
+ /* likely the wrong endianness, A0? */
+ return -1;
+ }
+ qmrom_read(handle);
+ } else {
+ /* error? */
+ qmrom_b0_poll_soc(handle);
+ }
+ }
+
+ return retries > 0 ? 0 : -1;
+}
+
+static int qmrom_b0_poll_cmd_resp(struct qmrom_handle *handle)
+{
+ int retries = handle->comms_retries;
+
+ qmrom_b0_poll_soc(handle);
+ do {
+ if (handle->sstc->soc_flags.out_waiting) {
+ qmrom_pre_read(handle);
+ if (handle->sstc->len > 0xff) {
+ /* likely the wrong endianness, A0? */
+ return -1;
+ }
+ qmrom_read(handle);
+ break;
+ } else qmrom_b0_poll_soc(handle);
+ } while (retries--);
+
+ return retries > 0 ? 0 : -1;
+}
+
+int qmrom_b0_probe_device(struct qmrom_handle *handle)
+{
+ int rc, i;
+ uint8_t *soc_lcs_uuid;
+ handle->is_be = false;
+ check_stcs(__func__, __LINE__, handle);
+
+ qmrom_spi_set_freq(DEFAULT_SPI_CLOCKRATE);
+
+ rc = qmrom_reboot_bootloader(handle);
+ if (rc) {
+ LOG_ERR("%s: cannot reset the device...\n", __func__);
+ return rc;
+ }
+
+ rc = qmrom_b0_wait_ready(handle);
+ if (rc) {
+ LOG_INFO("%s: maybe not a B0 device\n", __func__);
+ return rc;
+ }
+
+ rc = qmrom_write_cmd(handle, ROM_CMD_B0_GET_CHIP_VER);
+ if (rc)
+ return rc;
+
+ rc = qmrom_b0_poll_cmd_resp(handle);
+ if (rc)
+ return rc;
+
+ handle->chip_rev = SSTC2UINT16(handle, CHIP_VERSION_CHIP_REV_PAYLOAD_OFFSET) & 0xFF;
+ handle->device_version = bswap_16(SSTC2UINT16(handle, CHIP_VERSION_DEV_REV_PAYLOAD_OFFSET));
+ if (handle->chip_rev != CHIP_REVISION_B0) {
+ LOG_ERR("%s: wrong chip revision 0x%x\n", __func__, handle->chip_rev);
+ handle->chip_rev = -1;
+ return -1;
+ }
+
+ rc = qmrom_b0_wait_ready(handle);
+ if (rc) {
+ LOG_ERR("%s: hmm something went wrong!!!\n", __func__);
+ return rc;
+ }
+
+ rc = qmrom_write_cmd(handle, ROM_CMD_B0_GET_SOC_INFO);
+ if (rc)
+ return rc;
+
+ rc = qmrom_b0_poll_cmd_resp(handle);
+ if (rc)
+ return rc;
+
+ /* skip the first byte */
+ soc_lcs_uuid = &(handle->sstc->payload[1]);
+ for (i = 0 ; i < ROM_SOC_ID_LEN ; i++)
+ handle->soc_id[i] = soc_lcs_uuid[ROM_SOC_ID_LEN - i - 1];
+ soc_lcs_uuid += ROM_SOC_ID_LEN;
+ handle->lcs_state = soc_lcs_uuid[0];
+ soc_lcs_uuid += 1;
+ for (i = 0 ; i < ROM_UUID_LEN ; i++)
+ handle->uuid[i] = soc_lcs_uuid[ROM_UUID_LEN - i - 1];
+
+ /* Set rom ops */
+ handle->rom_ops.flash_fw = qmrom_b0_flash_fw;
+ handle->rom_ops.flash_unstitched_fw = qmrom_b0_flash_unstitched_fw;
+ handle->rom_ops.flash_debug_cert = qmrom_b0_flash_debug_cert;
+ handle->rom_ops.erase_debug_cert = qmrom_b0_erase_debug_cert;
+
+ check_stcs(__func__, __LINE__, handle);
+ return 0;
+}
+
+static int qmrom_b0_flash_data(struct qmrom_handle *handle,
+ struct firmware *fw, uint8_t cmd, uint8_t resp)
+{
+ int rc, sent = 0;
+ const char *bin_data = (const char *)fw->data;
+
+ check_stcs(__func__, __LINE__, handle);
+ while (sent < fw->size) {
+ uint32_t tx_bytes = fw->size - sent;
+ if (tx_bytes > CHUNK_SIZE_B0)
+ tx_bytes = CHUNK_SIZE_B0;
+
+ LOG_DBG("%s: poll soc...\n", __func__);
+ check_stcs(__func__, __LINE__, handle);
+ qmrom_b0_poll_soc(handle);
+ qmrom_pre_read(handle);
+ qmrom_read(handle);
+
+ LOG_DBG("%s: sending %d command with %"PRIu32" bytes\n", __func__,
+ cmd, tx_bytes);
+ rc = qmrom_write_size_cmd(handle, cmd, tx_bytes, bin_data);
+ if (handle->sstc->payload[0] != resp) {
+ LOG_ERR("%s: wrong data result (%#x vs %#x)!!!\n",
+ __func__, handle->sstc->payload[0] & 0xff,
+ resp);
+ return SPI_PROTO_WRONG_RESP;
+ }
+ if (rc)
+ return rc;
+ sent += tx_bytes;
+ bin_data += tx_bytes;
+ check_stcs(__func__, __LINE__, handle);
+ }
+ return 0;
+}
+
+static int qmrom_b0_flash_fw(struct qmrom_handle *handle,
+ const struct firmware *fw)
+{
+ int rc = 0;
+ struct unstitched_firmware all_fws = { 0 };
+
+ rc = qmrom_unstitch_fw(fw, &all_fws, handle->chip_rev);
+ if (rc) {
+ LOG_ERR("%s: Unstitched fw flashing not supported yet\n", __func__);
+ return rc;
+ }
+ rc = qmrom_b0_flash_unstitched_fw(handle, &all_fws);
+ return rc;
+}
+
+static int qmrom_b0_flash_unstitched_fw(struct qmrom_handle *handle,
+ const struct unstitched_firmware *all_fws)
+{
+ int rc = 0;
+ uint8_t flash_cmd = handle->lcs_state == CC_BSV_SECURE_LCS ?
+ ROM_CMD_B0_SEC_LOAD_OEM_IMG_TO_RRAM : ROM_CMD_B0_SEC_LOAD_ICV_IMG_TO_RRAM;
+
+ if (all_fws->key1_crt->data[HBK_LOC] == HBK_2E_ICV &&
+ handle->lcs_state != CC_BSV_CHIP_MANUFACTURE_LCS) {
+ LOG_ERR("%s: Trying to flash an ICV fw on a non ICV platform\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (all_fws->key1_crt->data[HBK_LOC] == HBK_2E_OEM &&
+ handle->lcs_state != CC_BSV_SECURE_LCS) {
+ LOG_ERR("%s: Trying to flash an OEM fw on a non OEM platform\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ LOG_DBG("%s: starting...\n", __func__);
+ check_stcs(__func__, __LINE__, handle);
+
+ rc = qmrom_b0_wait_ready(handle);
+ if (rc) goto end;
+
+ check_stcs(__func__, __LINE__, handle);
+ LOG_DBG("%s: sending flash_cmd %u command\n", __func__, flash_cmd);
+ rc = qmrom_write_cmd(handle, flash_cmd);
+ if (rc) goto end;
+
+ check_stcs(__func__, __LINE__, handle);
+ rc = qmrom_b0_flash_data(handle, all_fws->key1_crt,
+ ROM_CMD_B0_CERT_DATA, WAITING_FOR_FIRST_KEY_CERT);
+ if (rc) goto end;
+
+ check_stcs(__func__, __LINE__, handle);
+ rc = qmrom_b0_flash_data(handle, all_fws->key2_crt,
+ ROM_CMD_B0_CERT_DATA, WAITING_FOR_SECOND_KEY_CERT);
+ if (rc) goto end;
+
+ check_stcs(__func__, __LINE__, handle);
+ rc = qmrom_b0_flash_data(handle, all_fws->fw_crt,
+ ROM_CMD_B0_CERT_DATA, WAITING_FOR_CONTENT_CERT);
+ if (rc) goto end;
+
+ check_stcs(__func__, __LINE__, handle);
+ rc = qmrom_b0_flash_data(handle, all_fws->fw_img,
+ ROM_CMD_B0_SEC_IMAGE_DATA, WAITING_FOR_SEC_FILE_DATA);
+
+ if (!rc) qmrom_msleep(SPI_READY_TIMEOUT_MS);
+
+end:
+ check_stcs(__func__, __LINE__, handle);
+ qmrom_free(all_fws->fw_img);
+ qmrom_free(all_fws->fw_crt);
+ qmrom_free(all_fws->key1_crt);
+ qmrom_free(all_fws->key2_crt);
+ return rc;
+}
+
+static int qmrom_b0_flash_debug_cert(struct qmrom_handle *handle,
+ struct firmware *dbg_cert)
+{
+ int rc;
+
+ LOG_DBG("%s: starting...\n", __func__);
+ check_stcs(__func__, __LINE__, handle);
+
+ rc = qmrom_b0_wait_ready(handle);
+ if (rc)
+ return rc;
+
+ check_stcs(__func__, __LINE__, handle);
+ LOG_DBG("%s: sending ROM_CMD_B0_WRITE_DBG_CERT command\n", __func__);
+ rc = qmrom_write_cmd(handle, ROM_CMD_B0_WRITE_DBG_CERT);
+ if (rc)
+ return rc;
+
+ check_stcs(__func__, __LINE__, handle);
+ LOG_DBG("%s: poll soc...\n", __func__);
+ qmrom_b0_poll_soc(handle);
+ qmrom_pre_read(handle);
+ qmrom_read(handle);
+
+ check_stcs(__func__, __LINE__, handle);
+ LOG_DBG("%s: sending ROM_CMD_B0_DEBUG_CERT_SIZE command\n", __func__);
+ rc = qmrom_write_size_cmd(handle, ROM_CMD_B0_DEBUG_CERT_SIZE,
+ sizeof(uint32_t), (const char *)&dbg_cert->size);
+ if (handle->sstc->payload[0] != WAITING_TO_DEBUG_CERTIFICATE_SIZE) {
+ LOG_ERR("%s: wrong debug cert size result (0x%x vs 0x%x)!!!\n",
+ __func__, handle->sstc->payload[0] & 0xff,
+ WAITING_TO_DEBUG_CERTIFICATE_SIZE);
+ return SPI_PROTO_WRONG_RESP;
+ }
+ if (rc)
+ return rc;
+
+ rc = qmrom_b0_flash_data(handle, dbg_cert,
+ ROM_CMD_B0_CERT_DATA, WAITING_FOR_DEBUG_CERT_DATA);
+ check_stcs(__func__, __LINE__, handle);
+ return 0;
+}
+
+static int qmrom_b0_erase_debug_cert(struct qmrom_handle *handle)
+{
+ int rc;
+
+ LOG_INFO("%s: starting...\n", __func__);
+ check_stcs(__func__, __LINE__, handle);
+
+ rc = qmrom_b0_wait_ready(handle);
+ if (!rc)
+ return rc;
+
+ LOG_DBG("%s: sending ROM_CMD_B0_ERASE_DBG_CERT command\n", __func__);
+ rc = qmrom_write_cmd(handle, ROM_CMD_B0_ERASE_DBG_CERT);
+ if (rc)
+ return rc;
+
+ qmrom_msleep(SPI_READY_TIMEOUT_MS);
+ check_stcs(__func__, __LINE__, handle);
+ return 0;
+}
diff --git a/libqmrom/src/qmrom_c0.c b/libqmrom/src/qmrom_c0.c
new file mode 100644
index 0000000..540c591
--- /dev/null
+++ b/libqmrom/src/qmrom_c0.c
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
+/*
+ * Copyright 2022 Qorvo US, Inc.
+ *
+ */
+
+#include <qmrom.h>
+#include <qmrom_spi.h>
+#include <qmrom_log.h>
+#include <qmrom_utils.h>
+#include <spi_rom_protocol.h>
+
+#define DEFAULT_SPI_CLOCKRATE 5000000
+#define CHIP_VERSION_CHIP_REV_PAYLOAD_OFFSET 4
+#define CHIP_VERSION_DEV_REV_PAYLOAD_OFFSET 6
+#define CHUNK_SIZE_C0 2040
+
+#define SPI_SH_READY_CMD_BIT_MASK_C0 (SPI_SH_READY_CMD_BIT_MASK >> 4 | SPI_SH_READY_CMD_BIT_MASK)
+
+enum C0_CMD {
+ ROM_CMD_C0_SEC_LOAD_ICV_IMG_TO_RRAM = 0x0,
+ ROM_CMD_C0_SEC_LOAD_OEM_IMG_TO_RRAM = 0x1,
+ ROM_CMD_C0_GET_CHIP_VER = 0x2,
+ ROM_CMD_C0_GET_SOC_INFO = 0x3,
+ ROM_CMD_C0_ERASE_DBG_CERT = 0x4,
+ ROM_CMD_C0_USE_DIRECT_RRAM_WR = 0X5,
+ ROM_CMD_C0_USE_INDIRECT_RRAM_WR = 0x6,
+ ROM_CMD_C0_WRITE_DBG_CERT = 0x7,
+ ROM_CMD_C0_SEC_IMAGE_DATA = 0x12,
+ ROM_CMD_C0_CERT_DATA = 0x13,
+ ROM_CMD_C0_DEBUG_CERT_SIZE = 0x14,
+};
+
+enum C0_RESP {
+ READY_FOR_CS_LOW_CMD = 0x00,
+ WRONG_CS_LOW_CMD = 0x01,
+ WAITING_FOR_NS_RRAM_FILE_SIZE = 0x02,
+ WAITING_FOR_NS_SRAM_FILE_SIZE = 0x03,
+ WAITING_FOR_NS_RRAM_FILE_DATA = 0x04,
+ WAITING_FOR_NS_SRAM_FILE_DATA = 0x05,
+ WAITING_FOR_SEC_FILE_DATA = 0x06,
+ ERR_NS_SRAM_OR_RRAM_SIZE_CMD = 0x07,
+ ERR_SEC_RRAM_SIZE_CMD = 0x08,
+ ERR_WAITING_FOR_NS_IMAGE_DATA_CMD = 0x09,
+ ERR_WAITING_FOR_SEC_IMAGE_DATA_CMD = 0x0A,
+ ERR_IMAGE_SIZE_IS_ZERO = 0x0B,
+ /* Got more data than expected size */
+ ERR_IMAGE_SIZE_TOO_BIG = 0x0C,
+ /* Image must divide in 16 without remainder */
+ ERR_IMAGE_IS_NOT_16BYTES_MUL = 0x0D,
+ ERR_GOT_DATA_MORE_THAN_ALLOWED = 0x0E,
+ /* Remainder is allowed only for last packet */
+ ERR_RRAM_DATA_REMAINDER_NOT_ALLOWED = 0x0F,
+ ERR_WAITING_FOR_CERT_DATA_CMD = 0x10,
+ WAITING_FOR_FIRST_KEY_CERT = 0x11,
+ WAITING_FOR_SECOND_KEY_CERT = 0x12,
+ WAITING_FOR_CONTENT_CERT = 0x13,
+ WAITING_FOR_DEBUG_CERT_DATA = 0x14,
+ ERR_FIRST_KEY_CERT_OR_FW_VER = 0x15,
+ ERR_SECOND_KEY_CERT = 0x16,
+ ERR_CONTENT_CERT_DOWNLOAD_ADDR = 0x17,
+ /* If the content certificate contains to much images */
+ ERR_TOO_MANY_IMAGES_IN_CONTENT_CERT = 0x18,
+ ERR_ADDRESS_NOT_DIVIDED_BY_8 = 0x19,
+ ERR_IMAGE_BOUNDARIES = 0x1A,
+ /* Expected ICV type and got OEM */
+ ERR_CERT_TYPE = 0x1B,
+ ERR_PRODUCT_ID = 0x1C,
+ ERR_RRAM_RANGE_OR_WRITE = 0x1D,
+ WAITING_TO_DEBUG_CERTIFICATE_SIZE = 0x1E,
+ ERR_DEBUG_CERT_SIZE = 0x1F,
+};
+
+static int qmrom_c0_flash_fw(struct qmrom_handle *handle,
+ const struct firmware *fw);
+static int qmrom_c0_flash_debug_cert(struct qmrom_handle *handle,
+ struct firmware *dbg_cert);
+static int qmrom_c0_erase_debug_cert(struct qmrom_handle *handle);
+
+#define qmrom_pre_read_c0(h) \
+ ({ \
+ int rc = qmrom_spi_wait_for_ready_line( \
+ (h)->ss_rdy_handle, SPI_READY_TIMEOUT_MS);\
+ if (!rc) rc = qmrom_pre_read((h)); \
+ rc; \
+ })
+#define qmrom_read_c0(h) \
+ ({ \
+ int rc = qmrom_spi_wait_for_ready_line( \
+ (h)->ss_rdy_handle, SPI_READY_TIMEOUT_MS);\
+ if (!rc) rc = qmrom_read((h)); \
+ rc; \
+ })
+#define qmrom_write_cmd_c0(h, cmd) \
+ ({ \
+ int rc = qmrom_spi_wait_for_ready_line( \
+ (h)->ss_rdy_handle, SPI_READY_TIMEOUT_MS);\
+ if (!rc) rc = qmrom_write_cmd((h), (cmd)); \
+ rc; \
+ })
+#define qmrom_write_cmd32_c0(h, cmd) \
+ ({ \
+ int rc = qmrom_spi_wait_for_ready_line( \
+ (h)->ss_rdy_handle, SPI_READY_TIMEOUT_MS);\
+ if (!rc) rc = qmrom_write_cmd32((h), (cmd)); \
+ rc; \
+ })
+#define qmrom_write_size_cmd_c0(h, cmd, ds, d) \
+ ({ \
+ int rc = qmrom_spi_wait_for_ready_line( \
+ (h)->ss_rdy_handle, SPI_READY_TIMEOUT_MS);\
+ if (!rc) rc = qmrom_write_size_cmd((h), (cmd), (ds), (d)); \
+ rc; \
+ })
+#define qmrom_write_size_cmd32_c0(h, cmd, ds, d) \
+ ({ \
+ int rc = qmrom_spi_wait_for_ready_line( \
+ (h)->ss_rdy_handle, SPI_READY_TIMEOUT_MS);\
+ if (!rc) rc = qmrom_write_size_cmd32((h), (cmd), (ds), (d)); \
+ rc; \
+ })
+
+static void qmrom_c0_poll_soc(struct qmrom_handle *handle)
+{
+ int retries = handle->comms_retries;
+ memset(handle->hstc, 0, sizeof(struct stc));
+ do {
+ int rc = qmrom_spi_wait_for_ready_line(handle->ss_rdy_handle, SPI_READY_TIMEOUT_MS);
+ if (rc) {
+ LOG_ERR("%s qmrom_spi_wait_for_ready_line failed\n", __func__);
+ continue;
+ }
+ qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ sizeof(struct stc) + handle->hstc->len);
+ } while (retries-- && handle->sstc->raw_flags == 0);
+}
+
+static int qmrom_c0_wait_ready(struct qmrom_handle *handle)
+{
+ int retries = handle->comms_retries;
+ qmrom_c0_poll_soc(handle);
+
+ /* handle->sstc has been updated */
+ while (retries-- &&
+ handle->sstc->raw_flags != SPI_SH_READY_CMD_BIT_MASK_C0)
+ {
+ if (handle->sstc->soc_flags.out_waiting) {
+ qmrom_pre_read_c0(handle);
+ qmrom_read_c0(handle);
+ } else if (handle->sstc->soc_flags.out_active) {
+ if (handle->sstc->len > 0xff) {
+ /* likely the wrong endianness, A0? */
+ return -1;
+ }
+ qmrom_read_c0(handle);
+ } else qmrom_c0_poll_soc(handle);
+ }
+ if (retries <= 0)
+ LOG_ERR("%s failed after %d replies\n", __func__, handle->comms_retries);
+
+ return retries > 0 ? 0 : -1;
+}
+
+static int qmrom_c0_poll_cmd_resp(struct qmrom_handle *handle)
+{
+ int retries = handle->comms_retries;
+
+ qmrom_c0_poll_soc(handle);
+ do {
+ if (handle->sstc->soc_flags.out_waiting) {
+ qmrom_pre_read_c0(handle);
+ if (handle->sstc->len > 0xff) {
+ /* likely the wrong endianness, A0? */
+ return -1;
+ }
+ qmrom_read_c0(handle);
+ break;
+ } else qmrom_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;
+}
+
+int qmrom_c0_probe_device(struct qmrom_handle *handle)
+{
+ int rc, i;
+ uint8_t *soc_lcs_uuid;
+
+ handle->is_be = false;
+
+ qmrom_spi_set_freq(DEFAULT_SPI_CLOCKRATE);
+
+ rc = qmrom_reboot_bootloader(handle);
+ if (rc) {
+ LOG_ERR("%s: cannot reset the device...\n", __func__);
+ return rc;
+ }
+
+ rc = qmrom_c0_wait_ready(handle);
+ if (rc) {
+ LOG_INFO("%s: maybe not a C0 device\n", __func__);
+ return rc;
+ }
+
+ rc = qmrom_write_cmd32_c0(handle, ROM_CMD_C0_GET_CHIP_VER);
+ if (rc)
+ return rc;
+
+ rc = qmrom_c0_poll_cmd_resp(handle);
+ if (rc)
+ return rc;
+
+ handle->chip_rev = SSTC2UINT16(handle, CHIP_VERSION_CHIP_REV_PAYLOAD_OFFSET) & 0xFF;
+ handle->device_version = bswap_16(SSTC2UINT16(handle, CHIP_VERSION_DEV_REV_PAYLOAD_OFFSET));
+ if (handle->chip_rev != CHIP_REVISION_C0) {
+ LOG_ERR("%s: wrong chip revision %#x\n", __func__, handle->chip_rev);
+ handle->chip_rev = -1;
+ return -1;
+ }
+
+ rc = qmrom_c0_wait_ready(handle);
+ if (rc) {
+ LOG_ERR("%s: hmm something went wrong!!!\n", __func__);
+ return rc;
+ }
+
+ rc = qmrom_write_cmd32_c0(handle, ROM_CMD_C0_GET_SOC_INFO);
+ if (rc)
+ return rc;
+
+ rc = qmrom_c0_poll_cmd_resp(handle);
+ if (rc)
+ return rc;
+
+ /* skip the first 4 bytes */
+ soc_lcs_uuid = &(handle->sstc->payload[4]);
+ for (i = 0 ; i < ROM_SOC_ID_LEN ; i++)
+ handle->soc_id[i] = soc_lcs_uuid[ROM_SOC_ID_LEN - i - 1];
+ soc_lcs_uuid += ROM_SOC_ID_LEN;
+ memcpy(&handle->lcs_state, soc_lcs_uuid, sizeof(uint32_t));
+ soc_lcs_uuid += 4;
+ for (i = 0 ; i < ROM_UUID_LEN ; i++)
+ handle->uuid[i] = soc_lcs_uuid[ROM_UUID_LEN - i - 1];
+
+ /* Set rom ops */
+ handle->rom_ops.flash_fw = qmrom_c0_flash_fw;
+ handle->rom_ops.flash_debug_cert = qmrom_c0_flash_debug_cert;
+ handle->rom_ops.erase_debug_cert = qmrom_c0_erase_debug_cert;
+
+ return 0;
+}
+
+static int qmrom_c0_flash_data(struct qmrom_handle *handle,
+ struct firmware *fw, uint8_t cmd, uint8_t resp, bool skip_last_check)
+{
+ int rc, sent = 0;
+ const char *bin_data = (const char *)fw->data;
+
+ while (sent < fw->size) {
+ uint32_t tx_bytes = fw->size - sent;
+ if (tx_bytes > CHUNK_SIZE_C0) tx_bytes = CHUNK_SIZE_C0;
+
+ LOG_DBG("%s: sending command %#x with %"PRIu32" bytes\n", __func__,
+ cmd, tx_bytes);
+ rc = qmrom_write_size_cmd32_c0(handle, cmd, tx_bytes, bin_data);
+ if (rc)
+ return rc;
+ sent += tx_bytes;
+ bin_data += tx_bytes;
+ if (skip_last_check && sent == fw->size) {
+ LOG_INFO("%s: flashing done, quitting now\n", __func__);
+ break;
+ }
+ qmrom_c0_poll_soc(handle);
+ qmrom_pre_read_c0(handle);
+ qmrom_read_c0(handle);
+ if (handle->sstc->payload[0] != resp) {
+ LOG_ERR("%s: wrong data result (%#x vs %#x)!!!\n",
+ __func__, handle->sstc->payload[0] & 0xff,
+ resp);
+ return SPI_PROTO_WRONG_RESP;
+ }
+ }
+ qmrom_msleep(SPI_READY_TIMEOUT_MS);
+ return 0;
+}
+
+static int qmrom_c0_flash_fw(struct qmrom_handle *handle,
+ const struct firmware *fw)
+{
+ int rc = 0;
+ struct unstitched_firmware all_fws = { 0 };
+ uint8_t flash_cmd = handle->lcs_state == CC_BSV_SECURE_LCS ?
+ ROM_CMD_C0_SEC_LOAD_OEM_IMG_TO_RRAM : ROM_CMD_C0_SEC_LOAD_ICV_IMG_TO_RRAM;
+
+ LOG_INFO("Unstitching the fw %p->data %p\n", (void*)fw, (void*)fw->data);
+ rc = qmrom_unstitch_fw(fw, &all_fws, handle->chip_rev);
+ if (rc) {
+ LOG_ERR("%s: Unstitched fw flashing not supported yet\n", __func__);
+ return rc;
+ }
+
+ if (all_fws.key1_crt->data[HBK_LOC] == HBK_2E_ICV &&
+ handle->lcs_state != CC_BSV_CHIP_MANUFACTURE_LCS) {
+ LOG_ERR("%s: Trying to flash an ICV fw on a non ICV platform\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (all_fws.key1_crt->data[HBK_LOC] == HBK_2E_OEM &&
+ handle->lcs_state != CC_BSV_SECURE_LCS) {
+ LOG_ERR("%s: Trying to flash an OEM fw on a non OEM platform\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ LOG_DBG("%s: starting...\n", __func__);
+
+ /* Set RRAM write mode */
+ rc = qmrom_c0_wait_ready(handle);
+ if (rc)
+ goto end;
+
+ rc = qmrom_write_cmd32_c0(handle, ROM_CMD_C0_USE_INDIRECT_RRAM_WR);
+ if (rc)
+ goto end;
+
+ qmrom_c0_poll_soc(handle);
+ qmrom_pre_read_c0(handle);
+ qmrom_read_c0(handle);
+ qmrom_c0_poll_soc(handle);
+
+ LOG_DBG("%s: sending flash_cmd %u command\n", __func__, flash_cmd);
+ rc = qmrom_write_cmd32_c0(handle, flash_cmd);
+ if (rc)
+ goto end;
+
+ qmrom_c0_poll_cmd_resp(handle);
+ if (handle->sstc->payload[0] != WAITING_FOR_FIRST_KEY_CERT) {
+ 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]);
+ goto end;
+ }
+
+ qmrom_c0_poll_soc(handle);
+
+ rc = qmrom_c0_flash_data(handle, all_fws.key1_crt,
+ ROM_CMD_C0_CERT_DATA, WAITING_FOR_SECOND_KEY_CERT, false);
+ if (rc)
+ goto end;
+
+ rc = qmrom_c0_flash_data(handle, all_fws.key2_crt,
+ ROM_CMD_C0_CERT_DATA, WAITING_FOR_CONTENT_CERT, false);
+ if (rc)
+ goto end;
+
+ rc = qmrom_c0_flash_data(handle, all_fws.fw_crt,
+ ROM_CMD_C0_CERT_DATA, WAITING_FOR_SEC_FILE_DATA, false);
+ if (rc)
+ goto end;
+
+ rc = qmrom_c0_flash_data(handle, all_fws.fw_img,
+ ROM_CMD_C0_SEC_IMAGE_DATA, WAITING_FOR_SEC_FILE_DATA, true);
+
+end:
+ qmrom_free(all_fws.fw_img);
+ qmrom_free(all_fws.fw_crt);
+ qmrom_free(all_fws.key1_crt);
+ qmrom_free(all_fws.key2_crt);
+ return rc;
+}
+
+static int qmrom_c0_flash_debug_cert(struct qmrom_handle *handle,
+ struct firmware *dbg_cert)
+{
+ int rc;
+
+ LOG_DBG("%s: starting...\n", __func__);
+ rc = qmrom_c0_wait_ready(handle);
+ if (rc)
+ return rc;
+
+ LOG_DBG("%s: sending ROM_CMD_C0_USE_DIRECT_RRAM_WR command\n", __func__);
+ rc = qmrom_write_cmd32_c0(handle, ROM_CMD_C0_USE_INDIRECT_RRAM_WR);
+ if (rc)
+ return rc;
+
+ qmrom_c0_poll_soc(handle);
+ qmrom_pre_read_c0(handle);
+ qmrom_read_c0(handle);
+ qmrom_c0_poll_soc(handle);
+
+ LOG_DBG("%s: sending ROM_CMD_C0_WRITE_DBG_CERT command\n", __func__);
+ rc = qmrom_write_cmd32_c0(handle, ROM_CMD_C0_WRITE_DBG_CERT);
+ if (rc)
+ return rc;
+ qmrom_c0_poll_cmd_resp(handle);
+ if (handle->sstc->payload[0] != WAITING_TO_DEBUG_CERTIFICATE_SIZE) {
+ LOG_ERR("%s: Waiting for WAITING_TO_DEBUG_CERTIFICATE_SIZE(%#x) but got %#x\n",
+ __func__, WAITING_TO_DEBUG_CERTIFICATE_SIZE, handle->sstc->payload[0]);
+ return rc;
+ }
+
+ LOG_DBG("%s: sending ROM_CMD_C0_DEBUG_CERT_SIZE command\n", __func__);
+ rc = qmrom_write_size_cmd32_c0(handle, ROM_CMD_C0_DEBUG_CERT_SIZE,
+ sizeof(uint32_t), (const char *)&dbg_cert->size);
+ qmrom_c0_poll_cmd_resp(handle);
+ if (handle->sstc->payload[0] != WAITING_FOR_DEBUG_CERT_DATA) {
+ LOG_ERR("%s: Waiting for WAITING_FOR_DEBUG_CERT_DATA(%#x) but got %#x\n",
+ __func__, WAITING_FOR_DEBUG_CERT_DATA, handle->sstc->payload[0]);
+ return rc;
+ }
+
+ rc = qmrom_c0_flash_data(handle, dbg_cert,
+ ROM_CMD_C0_CERT_DATA, WAITING_FOR_DEBUG_CERT_DATA, true);
+ return 0;
+}
+
+static int qmrom_c0_erase_debug_cert(struct qmrom_handle *handle)
+{
+ int rc;
+
+ LOG_DBG("%s: starting...\n", __func__);
+
+ rc = qmrom_c0_wait_ready(handle);
+ if (rc)
+ return rc;
+
+ LOG_DBG("%s: sending ROM_CMD_C0_ERASE_DBG_CERT command\n", __func__);
+ rc = qmrom_write_cmd32_c0(handle, ROM_CMD_C0_ERASE_DBG_CERT);
+ if (rc)
+ return rc;
+
+ qmrom_msleep(SPI_READY_TIMEOUT_MS);
+ return 0;
+}
diff --git a/libqmrom/src/qmrom_common.c b/libqmrom/src/qmrom_common.c
new file mode 100644
index 0000000..d5bac77
--- /dev/null
+++ b/libqmrom/src/qmrom_common.c
@@ -0,0 +1,421 @@
+// SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
+/*
+ * Copyright 2022 Qorvo US, Inc.
+ *
+ */
+
+#include <qmrom_utils.h>
+#include <qmrom_log.h>
+#include <qmrom_spi.h>
+#include <qmrom.h>
+#include <spi_rom_protocol.h>
+
+int qmrom_a0_probe_device(struct qmrom_handle *handle);
+int qmrom_b0_probe_device(struct qmrom_handle *handle);
+int qmrom_c0_probe_device(struct qmrom_handle *handle);
+
+static void qmrom_free_stcs(struct qmrom_handle *h)
+{
+ if (h->hstc)
+ qmrom_free(h->hstc);
+ if (h->sstc)
+ qmrom_free(h->sstc);
+}
+
+#ifdef CHECK_STCS
+void check_stcs(const char *func, int line, struct qmrom_handle *h)
+{
+ uint32_t *buff = (uint32_t *)h->hstc;
+ if (buff[MAX_STC_FRAME_LEN / sizeof(uint32_t)] != 0xfeeddeef) {
+ LOG_ERR("%s:%d - hstc %pK corrupted\n", func, line, (void*)h->hstc);
+ } else {
+ LOG_ERR("%s:%d - hstc %pK safe\n", func, line, (void*)h->hstc);
+ }
+ buff = (uint32_t *)h->sstc;
+ if (buff[MAX_STC_FRAME_LEN / sizeof(uint32_t)] != 0xfeeddeef) {
+ LOG_ERR("%s:%d - sstc %pK corrupted\n", func, line, (void*)h->sstc);
+ } else {
+ LOG_ERR("%s:%d - sstc %pK safe\n", func, line, (void*)h->sstc);
+ }
+}
+#endif
+
+static int qmrom_allocate_stcs(struct qmrom_handle *h)
+{
+ int rc = 0;
+ uint8_t *tx_buf = NULL, *rx_buf = NULL;
+
+ qmrom_alloc(tx_buf, MAX_STC_FRAME_LEN + sizeof(uint32_t));
+ if (tx_buf == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ qmrom_alloc(rx_buf, MAX_STC_FRAME_LEN + sizeof(uint32_t));
+ if (rx_buf == NULL) {
+ qmrom_free(tx_buf);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+#ifdef CHECK_STCS
+ ((uint32_t*)tx_buf)[MAX_STC_FRAME_LEN / sizeof(uint32_t)] = 0xfeeddeef;
+ ((uint32_t*)rx_buf)[MAX_STC_FRAME_LEN / sizeof(uint32_t)] = 0xfeeddeef;
+#endif
+ h->hstc = (struct stc *)tx_buf;
+ h->sstc = (struct stc *)rx_buf;
+ return rc;
+out:
+ qmrom_free_stcs(h);
+ return rc;
+}
+
+int qmrom_pre_read(struct qmrom_handle *handle)
+{
+ handle->hstc->all = 0;
+ handle->hstc->host_flags.pre_read = 1;
+ handle->hstc->ul = 1;
+ handle->hstc->len = 0;
+ handle->hstc->payload[0] = 0;
+ return qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ sizeof(struct stc) + handle->hstc->len);
+}
+
+int qmrom_read(struct qmrom_handle *handle)
+{
+ size_t rd_size = handle->sstc->len;
+ LOG_DBG("%s: reading %zu bytes...\n", __func__, rd_size);
+ memset(handle->hstc, 0, sizeof(struct stc) + rd_size);
+ handle->hstc->host_flags.read = 1;
+ handle->hstc->ul = 1;
+ handle->hstc->len = handle->sstc->len;
+
+ return qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ sizeof(struct stc) + rd_size);
+}
+
+int qmrom_write_cmd(struct qmrom_handle *handle, uint8_t cmd)
+{
+ handle->hstc->all = 0;
+ handle->hstc->host_flags.write = 1;
+ handle->hstc->ul = 1;
+ handle->hstc->len = 1;
+ handle->hstc->payload[0] = cmd;
+
+ return qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ sizeof(struct stc) + handle->hstc->len);
+}
+
+int qmrom_write_cmd32(struct qmrom_handle *handle, uint32_t cmd)
+{
+ handle->hstc->all = 0;
+ handle->hstc->host_flags.write = 1;
+ handle->hstc->ul = 1;
+ handle->hstc->len = sizeof(cmd);
+ memcpy(handle->hstc->payload, &cmd, sizeof(cmd));
+
+ return qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ sizeof(struct stc) + handle->hstc->len);
+}
+
+int qmrom_write_size_cmd(struct qmrom_handle *handle, uint8_t cmd,
+ uint16_t data_size, const char *data)
+{
+ handle->hstc->all = 0;
+ handle->hstc->host_flags.write = 1;
+ handle->hstc->ul = 1;
+ handle->hstc->len = data_size + 1;
+ handle->hstc->payload[0] = cmd;
+ memcpy(&handle->hstc->payload[1], data, data_size);
+
+ return qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ sizeof(struct stc) + handle->hstc->len);
+}
+
+int qmrom_write_size_cmd32(struct qmrom_handle *handle, uint32_t cmd,
+ uint16_t data_size, const char *data)
+{
+ handle->hstc->all = 0;
+ handle->hstc->host_flags.write = 1;
+ handle->hstc->ul = 1;
+ handle->hstc->len = data_size + sizeof(cmd);
+ memcpy(handle->hstc->payload, &cmd, sizeof(cmd));
+ memcpy(&handle->hstc->payload[sizeof(cmd)], data, data_size);
+
+ return qmrom_spi_transfer(handle->spi_handle,
+ (char *)handle->sstc, (const char *)handle->hstc,
+ sizeof(struct stc) + handle->hstc->len);
+}
+
+/*
+ * Unfortunately, A0, B0 and C0 have different
+ * APIs to get the chip version...
+ *
+ */
+int qmrom_probe_device(struct qmrom_handle *handle)
+{
+ int rc;
+
+ /* Test B0 first */
+ rc = qmrom_b0_probe_device(handle);
+ if (!rc)
+ return rc;
+
+ /* Test C0 next */
+ rc = qmrom_c0_probe_device(handle);
+ if (!rc)
+ return rc;
+
+ /* Finally try A0 */
+ rc = qmrom_a0_probe_device(handle);
+ if (!rc)
+ return rc;
+
+ /* None matched!!! */
+ return -1;
+}
+
+struct qmrom_handle *qmrom_init(void *spi_handle,
+ void *reset_handle,
+ void *ss_rdy_handle,
+ int comms_retries,
+ reset_device_fn reset)
+{
+ struct qmrom_handle *handle;
+ int rc;
+
+ qmrom_alloc(handle, sizeof(struct qmrom_handle));
+ if (!handle) {
+ LOG_ERR("%s: Couldn't allocate %zu bytes...\n", __func__,
+ sizeof(struct qmrom_handle));
+ return NULL;
+ }
+ rc = qmrom_allocate_stcs(handle);
+ if (rc) {
+ LOG_ERR("%s: Couldn't allocate stcs...\n", __func__);
+ qmrom_free(handle);
+ return NULL;
+ }
+
+ handle->spi_handle = spi_handle;
+ handle->reset_handle = reset_handle;
+ handle->ss_rdy_handle = ss_rdy_handle;
+ handle->comms_retries = comms_retries;
+ handle->chip_rev = CHIP_REVISION_UNKNOWN;
+ handle->device_version = -1;
+ handle->lcs_state = -1;
+
+ handle->dev_ops.reset = reset;
+
+ rc = qmrom_probe_device(handle);
+ if (rc) {
+ LOG_ERR("%s: qmrom_probe_device returned %d!\n", __func__, rc);
+ qmrom_free_stcs(handle);
+ qmrom_free(handle);
+ return NULL;
+ }
+
+ check_stcs(__func__, __LINE__, handle);
+ return handle;
+}
+
+void qmrom_deinit(struct qmrom_handle *handle)
+{
+ LOG_DBG("Deinitializing %pK\n", (void*)handle);
+ qmrom_free_stcs(handle);
+ qmrom_free(handle);
+}
+
+int qmrom_flash_dbg_cert(struct qmrom_handle *handle,
+ struct firmware *dbg_cert)
+{
+ if (!handle->rom_ops.flash_debug_cert) {
+ LOG_ERR("%s: flash debug certificate not support on this device\n",
+ __func__);
+ return -EINVAL;
+ }
+ return handle->rom_ops.flash_debug_cert(handle, dbg_cert);
+}
+
+int qmrom_erase_dbg_cert(struct qmrom_handle *handle)
+{
+ if (!handle->rom_ops.erase_debug_cert) {
+ LOG_ERR("%s: erase debug certificate not support on this device\n",
+ __func__);
+ return -EINVAL;
+ }
+ return handle->rom_ops.erase_debug_cert(handle);
+}
+
+int qmrom_flash_fw(struct qmrom_handle *handle,
+ const struct firmware *fw)
+{
+ return handle->rom_ops.flash_fw(handle, fw);
+}
+
+int qmrom_flash_unstitched_fw(struct qmrom_handle *handle,
+ const struct unstitched_firmware *fw)
+{
+ return handle->rom_ops.flash_unstitched_fw(handle, fw);
+}
+
+int qmrom_unstitch_fw(const struct firmware *fw,
+ struct unstitched_firmware *unstitched_fw,
+ enum chip_revision_e revision) {
+ uint32_t tot_len = 0;
+ uint32_t fw_img_sz = 0;
+ uint32_t fw_crt_sz = 0;
+ uint32_t key1_crt_sz = 0;
+ uint32_t key2_crt_sz = 0;
+ uint8_t *p_key1;
+ uint8_t *p_key2;
+ uint8_t *p_crt;
+ uint8_t *p_fw;
+ int ret = 0;
+
+ if (revision == CHIP_REVISION_A0) {
+ LOG_ERR("%s: A0, no unstitching!!!\n", __func__);
+ return -EINVAL;
+ }
+ if (fw->size < 2 * sizeof(key1_crt_sz)) {
+ LOG_ERR("%s: Not enough data (%zu) to unstitch\n", __func__, fw->size);
+ return -EINVAL;
+ }
+ LOG_INFO("%s: Unstitching %zu bytes\n", __func__, fw->size);
+
+ /* key1 */
+ key1_crt_sz = *(uint32_t * ) & fw->data[tot_len];
+ if (tot_len + key1_crt_sz + sizeof(key1_crt_sz) > fw->size) {
+ LOG_ERR("%s: Invalid or corrupted stitched file at offset \
+ %"PRIu32" (key1)\n", __func__, tot_len);
+ ret = -EINVAL;
+ goto out;
+ }
+ tot_len += sizeof(key1_crt_sz);
+ p_key1 = (uint8_t * ) & fw->data[tot_len];
+ tot_len += key1_crt_sz;
+
+ /* key2 */
+ key2_crt_sz = *(uint32_t * ) & fw->data[tot_len];
+ if (tot_len + key2_crt_sz + sizeof(key2_crt_sz) > fw->size) {
+ LOG_ERR("%s: Invalid or corrupted stitched file at offset \
+ %"PRIu32" (key2)\n", __func__, tot_len);
+ ret = -EINVAL;
+ goto out;
+ }
+ tot_len += sizeof(key2_crt_sz);
+ p_key2 = (uint8_t * ) & fw->data[tot_len];
+ tot_len += key2_crt_sz;
+
+ /* cert */
+ fw_crt_sz = *(uint32_t * ) & fw->data[tot_len];
+ if (tot_len + fw_crt_sz + sizeof(fw_crt_sz) > fw->size) {
+ LOG_ERR("%s: Invalid or corrupted stitched file at offset \
+ %"PRIu32" (content cert)\n", __func__, tot_len);
+ ret = -EINVAL;
+ goto out;
+ }
+ tot_len += sizeof(fw_crt_sz);
+ p_crt = (uint8_t * ) & fw->data[tot_len];
+ tot_len += fw_crt_sz;
+
+ /* fw */
+ fw_img_sz = *(uint32_t * ) & fw->data[tot_len];
+ if (tot_len + fw_img_sz + sizeof(fw_img_sz) != fw->size) {
+ LOG_ERR("%s: Invalid or corrupted stitched file at offset \
+ %"PRIu32" (firmnware)\n", __func__, tot_len);
+ ret = -EINVAL;
+ goto out;
+ }
+ tot_len += sizeof(fw_img_sz);
+ p_fw = (uint8_t * ) & fw->data[tot_len];
+
+ qmrom_alloc(unstitched_fw->fw_img,
+ fw_img_sz + sizeof(struct firmware));
+ if (unstitched_fw->fw_img == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ qmrom_alloc(unstitched_fw->fw_crt,
+ fw_crt_sz + sizeof(struct firmware));
+ if (unstitched_fw->fw_crt == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ qmrom_alloc(unstitched_fw->key1_crt,
+ key1_crt_sz + sizeof(struct firmware));
+ if (unstitched_fw->key1_crt == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ qmrom_alloc(unstitched_fw->key2_crt,
+ key2_crt_sz + sizeof(struct firmware));
+ if (unstitched_fw->key2_crt == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ unstitched_fw->key1_crt->data = (const uint8_t *)(unstitched_fw->key1_crt + 1);
+ unstitched_fw->key2_crt->data = (const uint8_t *)(unstitched_fw->key2_crt + 1);
+ unstitched_fw->fw_crt->data = (const uint8_t *)(unstitched_fw->fw_crt + 1);
+ unstitched_fw->fw_img->data = (const uint8_t *)(unstitched_fw->fw_img + 1);
+ unstitched_fw->key1_crt->size = key1_crt_sz;
+ unstitched_fw->key2_crt->size = key2_crt_sz;
+ unstitched_fw->fw_crt->size = fw_crt_sz;
+ unstitched_fw->fw_img->size = fw_img_sz;
+
+ memcpy((void *)unstitched_fw->key1_crt->data, p_key1, key1_crt_sz);
+ memcpy((void *)unstitched_fw->key2_crt->data, p_key2, key2_crt_sz);
+ memcpy((void *)unstitched_fw->fw_crt->data, p_crt, fw_crt_sz);
+ memcpy((void *)unstitched_fw->fw_img->data, p_fw, fw_img_sz);
+ return 0;
+
+err:
+ if (unstitched_fw->fw_img)
+ qmrom_free(unstitched_fw->fw_img);
+ if (unstitched_fw->fw_crt)
+ qmrom_free(unstitched_fw->fw_crt);
+ if (unstitched_fw->key1_crt)
+ qmrom_free(unstitched_fw->key1_crt);
+ if (unstitched_fw->key2_crt)
+ qmrom_free(unstitched_fw->key2_crt);
+
+out:
+ return ret;
+}
+
+int qmrom_reboot_bootloader(struct qmrom_handle *handle)
+{
+ int rc;
+
+ rc = qmrom_spi_set_cs_level(handle->spi_handle, 0);
+ if (rc) {
+ LOG_ERR("%s: spi_set_cs_level(0) failed with %d\n", __func__,
+ rc);
+ return rc;
+ }
+ qmrom_msleep(SPI_RST_LOW_DELAY_MS);
+
+ handle->dev_ops.reset(handle->reset_handle);
+
+ qmrom_msleep(SPI_RST_LOW_DELAY_MS);
+
+ rc = qmrom_spi_set_cs_level(handle->spi_handle, 1);
+ if (rc) {
+ LOG_ERR("%s: spi_set_cs_level(1) failed with %d\n", __func__,
+ rc);
+ return rc;
+ }
+
+ qmrom_msleep(SPI_RST_LOW_DELAY_MS);
+
+ return 0;
+}
diff --git a/libqmrom/src/spi_rom_protocol.c b/libqmrom/src/spi_rom_protocol.c
deleted file mode 100644
index a627eaa..0000000
--- a/libqmrom/src/spi_rom_protocol.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2021 Qorvo US, Inc.
- *
- * SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
- *
- * This file is provided under the Apache License 2.0, or the
- * GNU General Public License v2.0.
- *
- */
-#include <spi_rom_protocol.h>
-#include <qmrom_utils.h>
-#include <qmrom_log.h>
-#include <qmrom_spi.h>
-#include <qmrom.h>
-
-#ifdef __KERNEL__
-#include <linux/kernel.h>
-#define bswap_16 cpu_to_be16
-#else
-#include <byteswap.h>
-#endif
-
-static const char *rom_code_b0_responses_str[] = {
- "res_READY_FOR_CS_LOW_CMD",
- "res_WRONG_CS_LOW_CMD",
- "res_WAITING_FOR_NS_RRAM_FILE_SIZE",
- "res_WAITING_FOR_NS_SRAM_FILE_SIZE",
- "res_WAITING_FOR_NS_RRAM_FILE_DATA",
- "res_WAITING_FOR_NS_SRAM_FILE_DATA", // 5
- "res_WAITING_FOR_SEC_FILE_DATA",
- "res_ERR_NS_SRAM_OR_RRAM_SIZE_CMD",
- "res_ERR_SEC_RRAM_SIZE_CMD",
- "res_ERR_WAITING_FOR_NS_IMAGE_DATA_CMD",
- "res_ERR_WAITING_FOR_SEC_IMAGE_DATA_CMD", // 10
- "res_ERR_IMAGE_SIZE_IS_ZERO",
- "res_ERR_IMAGE_SIZE_TOO_BIG", /*Got more data than expected size*/
- "res_ERR_IMAGE_IS_NOT_16BYTES_MUL", /*Image must divide in 16 without remainder*/
- "res_ERR_GOT_DATA_MORE_THAN_ALLOWED",
- "res_ERR_RRAM_DATA_REMAINDER_NOT_ALLOWED", // 15 /*Remainder is allowed only for last packet*/
- "res_ERR_WAITING_FOR_CERT_DATA_CMD",
- "res_WAITING_FOR_FIRST_KEY_CERT",
- "res_WAITING_FOR_SECOND_KEY_CERT",
- "res_WAITING_FOR_CONTENT_CERT",
- "res_WAITING_FOR_DEBUG_CERT_DATA", // 20
- "res_ERR_FIRST_KEY_CERT_OR_FW_VER",
- "res_ERR_SECOND_KEY_CERT",
- "res_ERR_CONTENT_CERT_DOWNLOAD_ADDR",
- "res_ERR_TOO_MANY_IMAGES_IN_CONTENT_CERT",/*If the content certificate contains to much images*/
- "res_ERR_ADDRESS_NOT_DIVIDED_BY_8", //25
- "res_ERR_IMAGE_BOUNDARIES",
- "res_ERR_CERT_TYPE", /* Expected ICV type and got OEM */
- "res_ERR_PRODUCT_ID",
- "res_ERR_RRAM_RANGE_OR_WRITE",
- "res_WAITING_TO_DEBUG_CERTIFICATE_SIZE", // 30
- "res_ERR_DEBUG_CERT_SIZE"
-};
-static const int rom_code_b0_responses_nb =
- sizeof(rom_code_b0_responses_str) / sizeof(char *);
-_Static_assert(sizeof(rom_code_b0_responses_str) / sizeof(char *) == 32, "Wrong array size");
-
-
-int spi_proto_prepare_write_cmd(void *spi_handle, int do_exp_resp,
- uint8_t exp_resp, int read_len,
- struct stc *sstc, struct stc *hstc,
- enum chip_revision_e revision)
-{
- uint8_t dev_ready_flag = SPI_DEVICE_READY_FLAGS;
- int rc;
-
- if (revision == CHIP_REVISION_A0) {
- qmrom_spi_set_freq(DEFAULT_SPI_CLOCKRATE_A0);
- }
- else {
- qmrom_spi_set_freq(DEFAULT_SPI_CLOCKRATE);
- }
-
- rc = spi_proto_wait_for_device_flag(spi_handle,
- dev_ready_flag,
- sstc, hstc,
- SPI_DEVICE_POLL_RETRY);
- if (rc) {
- LOG_ERR("%s: spi_proto_wait_for_device_flag(%x) failed with %d\n",
- __func__, dev_ready_flag, rc);
- return rc;
- }
-
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.pre_read = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- hstc->len = 0;
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, revision);
- if (rc) {
- LOG_ERR("%s: pre-read failed with %d\n", __func__, rc);
- return rc;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "pre-read\n");
-
- hstc->all = 0;
- sstc->all = 0;
- hstc->host_flags.read = 1;
- hstc->ul = SPI_UL_ROM_BOOT_PROTO;
- hstc->len = read_len;
- /* hstc paylaod shall be set by the caller */
- rc = spi_proto_send_stc(spi_handle, sstc, hstc, revision);
- if (rc) {
- LOG_ERR("%s: read failed with %d\n", __func__, rc);
- return rc;
- }
- dump_raw_hsstc(LOG_DBG, hstc, sstc, "read\n");
- if (do_exp_resp && sstc->payload[0] != exp_resp) {
- if ((revision == CHIP_REVISION_B0) &&
- (exp_resp < rom_code_b0_responses_nb) &&
- (sstc->payload[0] < rom_code_b0_responses_nb))
- {
- LOG_ERR("%s: rom code answered %s(0x%02x) vs %s(0x%02x) expected\n",
- __func__, rom_code_b0_responses_str[sstc->payload[0]],
- sstc->payload[0],
- rom_code_b0_responses_str[exp_resp], exp_resp);
- } else {
- LOG_ERR("%s: rom code answered 0x%02x vs 0x%02x expected -- 0x%x 0x%x\n",
- __func__, sstc->payload[0], exp_resp, rom_code_b0_responses_nb, revision);
- }
- return SPI_PROTO_WRONG_RESP;
- }
- return 0;
-}
-
-int spi_proto_wait_for_device_flag(void *spi_handle, uint8_t flag_mask,
- struct stc *sstc, struct stc *hstc,
- int retries)
-{
- uint8_t tx_buffer[16], rx_buffer[16];
- int rc;
-
- tx_buffer[0] = 0;
- rc = qmrom_spi_wait_for_ready_line(spi_handle, SPI_READY_TIMEOUT_MS);
- if (rc)
- return rc;
- do {
- rc = qmrom_spi_transfer(spi_handle, (char *)rx_buffer,
- (char *)tx_buffer, 1);
- if (rc)
- return rc;
- dump_raw_buffer(LOG_DBG, tx_buffer, rx_buffer, 1, "Device ready\n");
- if ((rx_buffer[0] & flag_mask) == flag_mask)
- return 0;
- qmrom_msleep(SPI_INTERCMD_DELAY_MS);
- } while (--retries > 0);
- return PEG_ERR_TIMEOUT;
-}
-
-int spi_proto_send_stc(void *spi_handle, struct stc *sstc,
- const struct stc *hstc, enum chip_revision_e revision)
-{
- int rc = qmrom_spi_transfer(spi_handle, (char *)sstc, (const char *)hstc,
- sizeof(struct stc) + hstc->len);
- if (rc) {
- LOG_ERR("%s: qmrom_spi_transfer failed: error %d\n", __func__, rc);
- return rc;
- }
- if (revision == CHIP_REVISION_A0) {
- sstc->len = bswap_16(sstc->len);
- }
- return 0;
-}
diff --git a/qm35-spi.c b/qm35-spi.c
index 95d57ee..c5e30b8 100644
--- a/qm35-spi.c
+++ b/qm35-spi.c
@@ -56,6 +56,7 @@
#include "hsspi_test.h"
#define QM35_REGULATOR_DELAY_US 1000
+#define QMROM_RETRIES 10
static int qm_firmware_load(struct qm35_ctx *qm35_hdl);
static void qm35_regulators_set(struct qm35_ctx *qm35_hdl, bool on);
@@ -88,7 +89,16 @@ static bool wake_use_csn = false;
module_param(wake_use_csn, bool, 0444);
MODULE_PARM_DESC(wake_use_csn, "Use HSSPI CSn pin to wake up QM35");
+int trace_spi_xfers;
+module_param(trace_spi_xfers, int, 0444);
+MODULE_PARM_DESC(trace_spi_xfers, "Trace all the SPI transfers");
+
+int qmrom_retries = QMROM_RETRIES;
+module_param(qmrom_retries, int, 0444);
+MODULE_PARM_DESC(qmrom_retries, "QMROM retries");
+
static uint8_t qm_soc_id[ROM_SOC_ID_LEN];
+static uint16_t qm_dev_id;
/*
* uci_open() : open operation for uci device
@@ -398,38 +408,65 @@ static int qm_firmware_load(struct qm35_ctx *qm35_hdl)
{
struct spi_device *spi = qm35_hdl->spi;
unsigned int state = qm35_get_state(qm35_hdl);
+ const struct firmware *fw;
+ struct qmrom_handle *h;
int ret;
- uint8_t uuid[ROM_UUID_LEN];
- uint8_t lcs_state = CC_BSV_SECURE_LCS;
qm35_set_state(qm35_hdl, QM35_CTRL_STATE_FW_DOWNLOADING);
qmrom_set_log_device(&spi->dev, LOG_WARN);
- dev_info(&spi->dev, "Get device info\n");
- ret = qmrom_get_soc_info(&spi->dev, qmrom_spi_reset_device, qm35_hdl,
- qm_soc_id, uuid, &lcs_state);
- if (!ret) {
- dev_info(&spi->dev, " devid: %*phN\n", ROM_SOC_ID_LEN, qm_soc_id);
- dev_info(&spi->dev, " uuid: %*phN\n", ROM_UUID_LEN, uuid);
- dev_info(&spi->dev, " lcs_state: %hhu\n", lcs_state);
+ h = qmrom_init(&spi->dev,
+ qm35_hdl,
+ qm35_hdl->gpio_ss_rdy,
+ qmrom_retries,
+ qmrom_spi_reset_device);
+ if (!h) {
+ pr_err("qmrom_init failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ dev_info(&spi->dev, " chip_ver: %x\n", h->chip_rev);
+ dev_info(&spi->dev, " dev_id: deca%04x\n", h->device_version);
+
+ if (h->chip_rev != CHIP_REVISION_A0) {
+ dev_info(&spi->dev, " soc_id: %*phN\n", ROM_SOC_ID_LEN, h->soc_id);
+ dev_info(&spi->dev, " uuid: %*phN\n", ROM_UUID_LEN, h->uuid);
+ dev_info(&spi->dev, " lcs_state: %hhu\n", h->lcs_state);
+
+ memcpy(&qm_dev_id, &h->device_version, sizeof(qm_dev_id));
+ memcpy(qm_soc_id, h->soc_id, ROM_SOC_ID_LEN);
+
+ debug_soc_info_available(&qm35_hdl->debug);
+ } else {
+ dev_dbg(&spi->dev, "SoC info not supported on chip revision A0\n");
}
- dev_info(&spi->dev, "Starting device flashing!\n");
- ret = qmrom_download_fw(spi, qmrom_spi_get_firmware,
- qmrom_spi_release_firmware,
- qmrom_spi_reset_device, qm35_hdl, 0, lcs_state);
+ dev_dbg(&spi->dev, "Starting device flashing!\n");
+ fw = qmrom_spi_get_firmware(&spi->dev,
+ h->chip_rev, h->lcs_state);
+ ret = qmrom_flash_fw(h, fw);
+ qmrom_spi_release_firmware(fw);
if (ret)
dev_err(&spi->dev, "Firmware download failed!\n");
else
dev_info(&spi->dev, "Device flashing completed!\n");
+out:
qm35_set_state(qm35_hdl, state);
return ret;
}
+int qm_get_dev_id(struct qm35_ctx *qm35_hdl, uint16_t *dev_id)
+{
+ memcpy(dev_id, &qm_dev_id, sizeof(qm_dev_id));
+
+ return 0;
+}
+
int qm_get_soc_id(struct qm35_ctx *qm35_hdl, uint8_t *soc_id)
{
memcpy(soc_id, qm_soc_id, ROM_SOC_ID_LEN);
@@ -651,10 +688,14 @@ static int qm35_probe(struct spi_device *spi)
qm35_ctx->state = QM35_CTRL_STATE_UNKNOWN;
- if (flash_on_probe) {
- ret = qm_firmware_load(qm35_ctx);
- if (ret)
- goto poweroff;
+ /* 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
+ */
+ ret = debug_init_root(&qm35_ctx->debug, NULL);
+ if (ret) {
+ debug_deinit(&qm35_ctx->debug);
+ goto poweroff;
}
ret = hsspi_init(&qm35_ctx->hsspi, spi);
@@ -665,7 +706,7 @@ static int qm35_probe(struct spi_device *spi)
if (ret)
goto hsspi_deinit;
- ret = debug_init(&qm35_ctx->debug, NULL);
+ ret = debug_init(&qm35_ctx->debug);
if (ret)
goto uci_layer_deinit;
@@ -695,6 +736,12 @@ static int qm35_probe(struct spi_device *spi)
if (ret)
goto log_layer_unregister;
+ if (flash_on_probe) {
+ ret = qm_firmware_load(qm35_ctx);
+ if (ret)
+ goto log_layer_unregister;
+ }
+
hsspi_start(&qm35_ctx->hsspi);
/* we can have missed an edge */
diff --git a/qm35.h b/qm35.h
index f8592c1..02796ac 100644
--- a/qm35.h
+++ b/qm35.h
@@ -83,6 +83,7 @@ static inline int qm35_reset(struct qm35_ctx *qm35_hdl, int timeout_ms)
return -ENODEV;
}
+int qm_get_dev_id(struct qm35_ctx *qm35_hdl, uint16_t *dev_id);
int qm_get_soc_id(struct qm35_ctx *qm35_hdl, uint8_t *soc_id);
void qm35_hsspi_start(struct qm35_ctx *qm35_hdl);
diff --git a/qmrom_spi.c b/qmrom_spi.c
index 123c534..8f3f2e7 100644
--- a/qmrom_spi.c
+++ b/qmrom_spi.c
@@ -34,8 +34,8 @@
#include "qm35.h"
static const char *fwname = NULL;
-// Initialize to the lowest default frequency
-static unsigned int speed_hz = DEFAULT_SPI_CLOCKRATE_A0;
+static unsigned int speed_hz;
+extern int trace_spi_xfers;
void qmrom_set_fwname(const char *name)
{
@@ -45,6 +45,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;
+ int rc;
struct spi_transfer xfer[] = {
{
@@ -55,7 +56,16 @@ int qmrom_spi_transfer(void *handle, char *rbuf, const char *wbuf, size_t size)
},
};
- return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
+ rc = spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
+
+ if (trace_spi_xfers) {
+ print_hex_dump(KERN_DEBUG, "tx:", DUMP_PREFIX_NONE,
+ 16, 1, wbuf, size, false);
+ print_hex_dump(KERN_DEBUG, "rx:", DUMP_PREFIX_NONE,
+ 16, 1, rbuf, size, false);
+ }
+
+ return rc;
}
int qmrom_spi_set_cs_level(void *handle, int level)
@@ -96,8 +106,7 @@ const struct firmware *qmrom_spi_get_firmware(void *handle,
if (revision == CHIP_REVISION_A0)
snprintf(_fw_name, sizeof(_fw_name), "qm35_%02x.bin", revision);
else
- snprintf(_fw_name, sizeof(_fw_name), "qm35_%02x_%.3s.bin",
- revision,
+ snprintf(_fw_name, sizeof(_fw_name), "qm35_b0_%.3s.bin",
lcs_state == CC_BSV_SECURE_LCS ? "oem" : "icv");
} else {
fw_name = fwname;
@@ -123,12 +132,13 @@ void qmrom_spi_release_firmware(const struct firmware *fw)
release_firmware(fw);
}
-// FIXME: wait for ss ready mock
int qmrom_spi_wait_for_ready_line(void *handle, unsigned int timeout_ms)
{
- usleep_range(timeout_ms * 1000, timeout_ms * 1000);
-
- return 0;
+ int count_down = (int)timeout_ms;
+ while (!gpiod_get_value(handle) && (--count_down >= 0)) {
+ usleep_range(1000, 1100);
+ }
+ return gpiod_get_value(handle) ? 0 : -1;
}
void qmrom_spi_set_freq(unsigned int freq)