[PATCH 19/25] efw-downloader: efw-commands: add support for commands in flash category
Takashi Sakamoto
o-takashi at sakamocchi.jp
Fri Aug 21 09:31:05 CEST 2020
Fireworks protocol includes command for software to operate on-board flash
memory.
This commit implements the command and adds local helper functions.
Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
---
efw-downloader/src/efw-commands.c | 213 ++++++++++++++++++++++++++++++
efw-downloader/src/efw-commands.h | 12 ++
2 files changed, 225 insertions(+)
diff --git a/efw-downloader/src/efw-commands.c b/efw-downloader/src/efw-commands.c
index 08b0114..b0a8320 100644
--- a/efw-downloader/src/efw-commands.c
+++ b/efw-downloader/src/efw-commands.c
@@ -8,10 +8,26 @@
// Categories in Echo Audio Fireworks protocol.
#define CATEGORY_HW 0
+#define CATEGORY_FLASH 1
// Commands in hardware category.
#define HW_CMD_INFO 0
+// Commands in flash category.
+#define FLASH_CMD_ERASE 0
+#define FLASH_CMD_READ 1
+#define FLASH_CMD_WRITE 2
+#define FLASH_CMD_STATE 3
+#define FLASH_CMD_SESSION_BASE 4
+#define FLASH_CMD_LOCK 5
+
+#define EFW_FLASH_FRAME_MAX_QUADS 64
+
+// Between 0x00000000 - 0x00010000.
+#define EFW_FLASH_BLOCK_SIZE_LOW 0x00002000
+// Between 0x00010000 - 0x00200000.
+#define EFW_FLASH_BLOCK_SIZE_HIGH 0x00010000
+
#define TIMEOUT 200
#define CAP_HAS_DSP 0x00000010
@@ -28,3 +44,200 @@ void efw_hw_info_has_fpga(struct hw_info *info, gboolean *has_fpga)
{
*has_fpga = !!(info->flags & CAP_HAS_FPGA);
}
+
+int efw_flash_get_block_size(size_t offset, size_t *block_size)
+{
+ if (offset < 0x00010000)
+ *block_size = EFW_FLASH_BLOCK_SIZE_LOW;
+ else if (offset < 0x00200000)
+ *block_size = EFW_FLASH_BLOCK_SIZE_HIGH;
+ else
+ return -ENXIO;
+
+ return 0;
+}
+
+void efw_flash_erase(EfwProto *proto, size_t offset, GError **error)
+{
+ size_t block_size;
+ guint32 args[1] = {0};
+ guint32 *params = (guint32 [1]){0};
+ gsize param_count = 1;
+ int err;
+
+ err = efw_flash_get_block_size(offset, &block_size);
+ if (err < 0) {
+ g_set_error(error, EFW_PROTO_ERROR, -err,
+ "%s %d: %s", __FILE__, __LINE__, strerror(-err));
+ return;
+ }
+
+ if (offset % block_size > 0) {
+ g_set_error(error, EFW_PROTO_ERROR, EINVAL,
+ "%s %d: %s", __FILE__, __LINE__, strerror(EINVAL));
+ return;
+ }
+
+ args[0] = offset;
+ efw_proto_transaction(proto, CATEGORY_FLASH, FLASH_CMD_ERASE, args, G_N_ELEMENTS(args),
+ (guint32 *const *)¶ms, ¶m_count, TIMEOUT, error);
+}
+
+void efw_flash_erase_and_wait(EfwProto *proto, size_t offset, GError **error)
+{
+ efw_flash_erase(proto, offset, error);
+ if (*error != NULL)
+ return;
+
+ while (TRUE) {
+ gboolean state;
+ struct timespec req = {
+ .tv_sec = 0,
+ .tv_nsec = 500000000,
+ };
+
+ efw_flash_state(proto, &state, error);
+ if (state == TRUE)
+ break;
+
+ if (*error != NULL)
+ g_clear_error(error);
+
+ clock_nanosleep(CLOCK_MONOTONIC, 0, &req, NULL);
+ }
+}
+
+void efw_flash_read(EfwProto *proto, size_t offset, guint32 *buf, size_t quads, GError **error)
+{
+ guint32 args[2] = {0};
+ guint32 *params = (guint32 [2 + EFW_FLASH_FRAME_MAX_QUADS]){0};
+ gsize param_count = 2 + EFW_FLASH_FRAME_MAX_QUADS;
+
+ if (quads > EFW_FLASH_FRAME_MAX_QUADS) {
+ g_set_error(error, EFW_PROTO_ERROR, EINVAL,
+ "%s %d: %s", __FILE__, __LINE__, strerror(EINVAL));
+ return;
+ }
+
+ args[0] = offset;
+ args[1] = quads;
+
+ efw_proto_transaction(proto, CATEGORY_FLASH, FLASH_CMD_READ, args, G_N_ELEMENTS(args),
+ (guint32 *const *)¶ms, ¶m_count, TIMEOUT, error);
+ if (*error != NULL)
+ return;
+
+ if (params[0] != offset || params[1] != quads) {
+ g_set_error(error, EFW_PROTO_ERROR, EIO,
+ "%s %d: %s", __FILE__, __LINE__, strerror(EIO));
+ return;
+ }
+
+ memcpy(buf, (const void *)¶ms[2], quads * sizeof(*buf));
+}
+
+void efw_flash_recursive_read(EfwProto *proto, size_t offset, guint32 *buf, size_t quads, GError **error)
+{
+ while (quads > 0) {
+ size_t count = MIN(quads, EFW_FLASH_FRAME_MAX_QUADS);
+
+ efw_flash_read(proto, offset, buf, count, error);
+ if (*error != NULL)
+ return;
+
+ offset += count * 4;
+ quads -= count;
+ buf += count;
+ }
+}
+
+void efw_flash_write(EfwProto *proto, size_t offset, guint32 *buf, size_t quads, GError **error)
+{
+ guint32 args[2 + EFW_FLASH_FRAME_MAX_QUADS] = {0};
+ guint32 *params = (guint32 [2]){0};
+ gsize param_count = 2;
+
+ if (quads > EFW_FLASH_FRAME_MAX_QUADS) {
+ g_set_error(error, EFW_PROTO_ERROR, EINVAL,
+ "%s %d: %s", __FILE__, __LINE__, strerror(EINVAL));
+ return;
+ }
+
+ args[0] = offset;
+ args[1] = quads;
+ memcpy((void *)&args[2], buf, quads * sizeof(*buf));
+
+ efw_proto_transaction(proto, CATEGORY_FLASH, FLASH_CMD_WRITE, args, G_N_ELEMENTS(args),
+ (guint32 *const *)¶ms, ¶m_count, TIMEOUT, error);
+}
+
+void efw_flash_recursive_write(EfwProto *proto, size_t offset, guint32 *buf, size_t quads, GError **error)
+{
+ while (quads > 0) {
+ size_t count = MIN(quads, EFW_FLASH_FRAME_MAX_QUADS);
+ gboolean state;
+
+ efw_flash_write(proto, offset, buf, count, error);
+ if (*error != NULL)
+ return;
+
+ offset += count * 4;
+ quads -= count;
+ buf += count;
+
+ while (TRUE) {
+ struct timespec req = {
+ .tv_sec = 0,
+ .tv_nsec = 500000000,
+ };
+
+ efw_flash_state(proto, &state, error);
+ if (state == TRUE)
+ break;
+
+ if (*error != NULL)
+ g_clear_error(error);
+
+ clock_nanosleep(CLOCK_MONOTONIC, 0, &req, NULL);
+ }
+ }
+}
+
+void efw_flash_state(EfwProto *proto, gboolean *state, GError **error)
+{
+ gsize param_count = 0;
+ efw_proto_transaction(proto, CATEGORY_FLASH, FLASH_CMD_STATE, NULL, 0, NULL, ¶m_count,
+ TIMEOUT, error);
+ if (*error == NULL) {
+ *state = TRUE;
+ } else if (g_error_matches(*error, EFW_PROTO_ERROR, HINAWA_SND_EFW_STATUS_FLASH_BUSY)) {
+ *state = FALSE;
+ g_clear_error(error);
+ }
+}
+
+void efw_flash_get_session_base(EfwProto *proto, size_t *offset, GError **error)
+{
+ guint32 *params = (guint32 [1]){0};
+ gsize param_count = 1;
+
+ efw_proto_transaction(proto, CATEGORY_FLASH, FLASH_CMD_SESSION_BASE, NULL, 0,
+ (guint32 *const *)¶ms, ¶m_count, TIMEOUT, error);
+ if (*error != NULL)
+ return;
+
+ *offset = params[0];
+}
+
+// MEMO: Lock operation is additional to the combination of IceLynx Micro and FPGA.
+void efw_flash_lock(EfwProto *proto, gboolean locked, GError **error)
+{
+ guint32 args[1] = {0};
+ guint32 *params = (guint32 [1]){0};
+ gsize param_count = 1;
+
+ args[0] = locked;
+
+ efw_proto_transaction(proto, CATEGORY_FLASH, FLASH_CMD_LOCK, args, G_N_ELEMENTS(args),
+ (guint32 *const *)¶ms, ¶m_count, TIMEOUT, error);
+}
diff --git a/efw-downloader/src/efw-commands.h b/efw-downloader/src/efw-commands.h
index fd2dbe3..a25781b 100644
--- a/efw-downloader/src/efw-commands.h
+++ b/efw-downloader/src/efw-commands.h
@@ -42,4 +42,16 @@ void efw_hw_info(EfwProto *proto, struct hw_info *info, GError **error);
void efw_hw_info_has_fpga(struct hw_info *info, gboolean *has_fpga);
+void efw_flash_erase(EfwProto *proto, size_t offset, GError **error);
+void efw_flash_read(EfwProto *proto, size_t offset, guint32 *buf, size_t quads, GError **error);
+void efw_flash_write(EfwProto *proto, size_t offset, guint32 *buf, size_t quads, GError **error);
+void efw_flash_state(EfwProto *proto, gboolean *state, GError **error);
+void efw_flash_get_session_base(EfwProto *proto, size_t *offset, GError **error);
+void efw_flash_lock(EfwProto *proto, gboolean locked, GError **error);
+
+int efw_flash_get_block_size(size_t offset, size_t *block_size);
+void efw_flash_erase_and_wait(EfwProto *proto, size_t offset, GError **error);
+void efw_flash_recursive_read(EfwProto *proto, size_t offset, guint32 *buf, size_t quads, GError **error);
+void efw_flash_recursive_write(EfwProto *proto, size_t offset, guint32 *buf, size_t quads, GError **error);
+
#endif
--
2.25.1
More information about the Alsa-devel
mailing list