aboutsummaryrefslogtreecommitdiffstats
path: root/src/sdiocmds.c
diff options
context:
space:
mode:
authorH. Gregor Molter <gregor.molter@secretlab.de>2023-02-20 19:52:36 -0500
committerKevin O'Connor <kevin@koconnor.net>2023-02-20 19:55:25 -0500
commitd7bd7f1f4ba6cecd19daa566fdc1864561269ae1 (patch)
treed57d02e2dd5fb12359b2ba95080241483f02fbb0 /src/sdiocmds.c
parent848a78d1a548cfe28af20d5d0ab021558368cfae (diff)
downloadkutter-d7bd7f1f4ba6cecd19daa566fdc1864561269ae1.tar.gz
kutter-d7bd7f1f4ba6cecd19daa566fdc1864561269ae1.tar.xz
kutter-d7bd7f1f4ba6cecd19daa566fdc1864561269ae1.zip
stm32: Add sdio support
Adds sdio support for the stm32f4 to allow for SD card flash updates without power cycling some boards, e.g. BTT Octopus Pro. Signed-off-by: H. Gregor Molter <gregor.molter@secretlab.de> Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/sdiocmds.c')
-rw-r--r--src/sdiocmds.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/sdiocmds.c b/src/sdiocmds.c
new file mode 100644
index 00000000..d9c020b4
--- /dev/null
+++ b/src/sdiocmds.c
@@ -0,0 +1,166 @@
+// Commands for sending messages on an SDIO bus
+//
+// Copyright (C) 2022 H. Gregor Molter <gregor.molter@secretlab.de>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include <string.h> // memcpy
+#include "board/gpio.h" // gpio_in_setup
+#include "board/sdio.h" // sdio_setup
+#include "basecmd.h" // oid_alloc
+#include "command.h" // DECL_COMMAND
+#include "sched.h" // DECL_SHUTDOWN
+
+struct sdiodev_s {
+ struct sdio_config sdio_config;
+ uint32_t blocksize;
+ uint32_t speed;
+ uint8_t data_buffer[4096];
+};
+
+#define TIMEOUT_MSEC 500
+
+void
+command_config_sdio(uint32_t *args)
+{
+ struct sdiodev_s *sdio = oid_alloc(args[0], command_config_sdio
+ , sizeof(*sdio));
+ sdio->blocksize = args[1];
+ sdio->speed = 400000; // Initial speed set to ~400khz
+}
+DECL_COMMAND(command_config_sdio, "config_sdio oid=%c blocksize=%u");
+
+struct sdiodev_s *
+sdiodev_oid_lookup(uint8_t oid)
+{
+ return oid_lookup(oid, command_config_sdio);
+}
+
+void
+command_sdio_set_bus(uint32_t *args)
+{
+ struct sdiodev_s *sdio = sdiodev_oid_lookup(args[0]);
+ sdio->sdio_config = sdio_setup(args[1]);
+}
+DECL_COMMAND(command_sdio_set_bus, "sdio_set_bus oid=%c sdio_bus=%u");
+
+void
+command_sdio_set_speed(uint32_t *args)
+{
+ struct sdiodev_s *sdio = sdiodev_oid_lookup(args[0]);
+ sdio->speed = args[1];
+ sdio_set_speed(sdio->sdio_config, sdio->speed);
+}
+DECL_COMMAND(command_sdio_set_speed, "sdio_set_speed oid=%c speed=%u");
+
+void
+command_sdio_send_command(uint32_t *args)
+{
+ uint8_t oid = args[0];
+ uint8_t cmd = args[1];
+ uint32_t argument = args[2];
+ uint8_t wait = args[3];
+ struct sdiodev_s *sdio = sdiodev_oid_lookup(oid);
+ uint8_t response[16];
+ uint8_t response_len = 0;
+ uint8_t err = sdio_send_command(sdio->sdio_config, cmd, argument, wait
+ , response, &response_len);
+ sendf("sdio_send_command_response oid=%c error=%c response=%*s"
+ , oid, err, response_len, response);
+}
+DECL_COMMAND(command_sdio_send_command
+ , "sdio_send_command oid=%c cmd=%c argument=%u wait=%c");
+
+void
+command_sdio_read_data(uint32_t *args)
+{
+ uint8_t oid = args[0];
+ uint8_t cmd = args[1];
+ uint32_t argument = args[2];
+ uint32_t data_len = 0;
+ struct sdiodev_s *sdio = sdiodev_oid_lookup(oid);
+ uint32_t timeout = TIMEOUT_MSEC*sdio->speed/1000;
+ uint8_t err = sdio_prepare_data_transfer(sdio->sdio_config, 1, 1
+ , sdio->blocksize, timeout);
+ if (err == 0) {
+ err = sdio_send_command(sdio->sdio_config, cmd, argument
+ , 1, NULL, NULL);
+ if (err == 0) {
+ data_len = sdio->blocksize;
+ if (data_len <= sizeof(sdio->data_buffer)) {
+ err = sdio_read_data(sdio->sdio_config, sdio->data_buffer
+ , 1, sdio->blocksize);
+ } else {
+ data_len = 0;
+ }
+ }
+ }
+ sendf("sdio_read_data_response oid=%c error=%c read=%u"
+ , oid, err, data_len);
+}
+DECL_COMMAND(command_sdio_read_data
+ , "sdio_read_data oid=%c cmd=%c argument=%u");
+
+void
+command_sdio_write_data(uint32_t *args)
+{
+ uint8_t oid = args[0];
+ uint8_t cmd = args[1];
+ uint32_t argument = args[2];
+ uint32_t data_len = 0;
+ struct sdiodev_s *sdio = sdiodev_oid_lookup(oid);
+ uint32_t timeout = TIMEOUT_MSEC*sdio->speed/1000;
+ uint8_t err = sdio_prepare_data_transfer(sdio->sdio_config, 0, 1
+ , sdio->blocksize, timeout);
+ if (err == 0) {
+ err = sdio_send_command(sdio->sdio_config, cmd, argument
+ , 1, NULL, NULL);
+ if (err == 0) {
+ data_len = sdio->blocksize;
+ if (data_len <= sizeof(sdio->data_buffer)) {
+ err = sdio_write_data(sdio->sdio_config, sdio->data_buffer
+ , 1, sdio->blocksize);
+ } else {
+ data_len = 0;
+ }
+ }
+ }
+ sendf("sdio_write_data_response oid=%c error=%c write=%u"
+ , oid, err, data_len);
+}
+DECL_COMMAND(command_sdio_write_data
+ , "sdio_write_data oid=%c cmd=%c argument=%u");
+
+void
+command_sdio_read_data_buffer(uint32_t *args)
+{
+ uint8_t oid = args[0];
+ uint32_t offset = args[1];
+ uint8_t len = args[2];
+ struct sdiodev_s *sdio = sdiodev_oid_lookup(oid);
+ uint8_t *buf = &(sdio->data_buffer[offset]);
+
+ if (offset + len > sizeof(sdio->data_buffer)) {
+ len = 0;
+ }
+ sendf("sdio_read_data_buffer_response oid=%c data=%*s", oid, len, buf);
+}
+DECL_COMMAND(command_sdio_read_data_buffer
+ , "sdio_read_data_buffer oid=%c offset=%u len=%c");
+
+void
+command_sdio_write_data_buffer(uint32_t *args)
+{
+ uint8_t oid = args[0];
+ uint32_t offset = args[1];
+ uint8_t write_data_len = args[2];
+ uint8_t *write_data = command_decode_ptr(args[3]);
+ struct sdiodev_s *sdio = sdiodev_oid_lookup(oid);
+ uint8_t *buf = &(sdio->data_buffer[offset]);
+
+ if (offset + write_data_len <= sizeof(sdio->data_buffer)) {
+ memcpy(buf, write_data, write_data_len);
+ }
+}
+DECL_COMMAND(command_sdio_write_data_buffer
+ , "sdio_write_data_buffer oid=%c offset=%u data=%*s");