[PATCH 19/25] efw-downloader: efw-commands: add support for commands in flash category

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxx>
---
 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 *)&params, &param_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 *)&params, &param_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 *)&params[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 *)&params, &param_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, &param_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 *)&params, &param_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 *)&params, &param_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




[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux