aboutsummaryrefslogtreecommitdiff
path: root/upgrade
diff options
context:
space:
mode:
authorGareth McMullin2012-01-18 20:45:18 +1300
committerGareth McMullin2012-01-18 20:46:35 +1300
commitf2f5fd2fa13f74560bb2cfd88417ad6c1e230988 (patch)
tree01a331d978102254287ea1cacbe3fd5a0d2768b8 /upgrade
parenta7f14e3cc008e2ef927dd2b3bc41f37cf1c21add (diff)
Added unfinished, untested upgrade tool.
Diffstat (limited to 'upgrade')
-rw-r--r--upgrade/Makefile22
-rw-r--r--upgrade/bindata.S28
-rw-r--r--upgrade/bindata.h32
-rw-r--r--upgrade/dfu.c150
-rw-r--r--upgrade/dfu.h86
-rw-r--r--upgrade/main.c160
-rw-r--r--upgrade/stm32mem.c97
-rw-r--r--upgrade/stm32mem.h30
8 files changed, 605 insertions, 0 deletions
diff --git a/upgrade/Makefile b/upgrade/Makefile
new file mode 100644
index 0000000..65d88e5
--- /dev/null
+++ b/upgrade/Makefile
@@ -0,0 +1,22 @@
+
+CC = $(CROSS_COMPILE)gcc
+
+CFLAGS = -Wall -Wextra -std=gnu99 -O0 -g -MD
+LDFLAGS = -lusb
+
+OBJ = bindata.o \
+ dfu.o \
+ stm32mem.o \
+ main.o
+
+all: bmp_upgrade
+
+bmp_upgrade: $(OBJ)
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+.PHONY: clean
+clean:
+ -rm -rf bmp_upgrade *.d *.o
+
+-include *.d
+
diff --git a/upgrade/bindata.S b/upgrade/bindata.S
new file mode 100644
index 0000000..1d94da5
--- /dev/null
+++ b/upgrade/bindata.S
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+.section .rodata
+.global _bindata, _bindatalen
+
+_bindata:
+ .incbin "../src/blackmagic.bin"
+
+_bindatalen:
+ .word . - _bindata
+
diff --git a/upgrade/bindata.h b/upgrade/bindata.h
new file mode 100644
index 0000000..3679692
--- /dev/null
+++ b/upgrade/bindata.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BINDATA_H
+#define __BINDATA_H
+
+#ifndef WIN32
+#define bindatalen _bindatalen
+#define bindata _bindata
+#endif
+
+extern const uint32_t bindatalen;
+extern const uint8_t bindata[];
+
+#endif
+
diff --git a/upgrade/dfu.c b/upgrade/dfu.c
new file mode 100644
index 0000000..2ab16ed
--- /dev/null
+++ b/upgrade/dfu.c
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <usb.h>
+
+#include "dfu.h"
+
+/* DFU Requests: Refer to Table 3.2 */
+#define DFU_DETACH 0x00
+#define DFU_DNLOAD 0x01
+#define DFU_UPLOAD 0x02
+#define DFU_GETSTATUS 0x03
+#define DFU_CLRSTATUS 0x04
+#define DFU_GETSTATE 0x05
+#define DFU_ABORT 0x06
+
+#define USB_DEFAULT_TIMEOUT 1000
+#define DFU_DETACH_TIMEOUT 1000
+
+int dfu_detach(usb_dev_handle *dev, uint16_t iface, uint16_t wTimeout)
+{
+ return usb_control_msg(dev,
+ USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ DFU_DETACH, wTimeout, iface, NULL, 0,
+ USB_DEFAULT_TIMEOUT);
+}
+
+int dfu_dnload(usb_dev_handle *dev, uint16_t iface,
+ uint16_t wBlockNum, void *data, uint16_t size)
+{
+ return usb_control_msg(dev,
+ USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ DFU_DNLOAD, wBlockNum, iface, data, size,
+ USB_DEFAULT_TIMEOUT);
+}
+
+int dfu_upload(usb_dev_handle *dev, uint16_t iface,
+ uint16_t wBlockNum, void *data, uint16_t size)
+{
+ return usb_control_msg(dev,
+ USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ DFU_DNLOAD, wBlockNum, iface, data, size,
+ USB_DEFAULT_TIMEOUT);
+}
+
+int dfu_getstatus(usb_dev_handle *dev, uint16_t iface, dfu_status *status)
+{
+ return usb_control_msg(dev,
+ USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ DFU_GETSTATUS, 0, iface, (void*)status, sizeof(dfu_status),
+ USB_DEFAULT_TIMEOUT);
+}
+
+int dfu_clrstatus(usb_dev_handle *dev, uint16_t iface)
+{
+ return usb_control_msg(dev,
+ USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ DFU_CLRSTATUS, 0, iface, NULL, 0, USB_DEFAULT_TIMEOUT);
+}
+
+int dfu_getstate(usb_dev_handle *dev, uint16_t iface)
+{
+ int i;
+ uint8_t state;
+ do {
+ i = usb_control_msg(dev,
+ USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ DFU_GETSTATE, 0, iface, &state, 1, USB_DEFAULT_TIMEOUT);
+ } while(i == 0);
+
+ if(i > 0)
+ return state;
+ else
+ return i;
+}
+
+int dfu_abort(usb_dev_handle *dev, uint16_t iface)
+{
+ return usb_control_msg(dev,
+ USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ DFU_ABORT, 0, iface, NULL, 0, USB_DEFAULT_TIMEOUT);
+}
+
+
+int dfu_makeidle(usb_dev_handle *dev, uint16_t iface)
+{
+ int i;
+ dfu_status status;
+
+ for(i = 0; i < 3; i++) {
+ if(dfu_getstatus(dev, iface, &status) < 0) {
+ dfu_clrstatus(dev, iface);
+ continue;
+ }
+
+ i--;
+
+ switch(status.bState) {
+ case STATE_DFU_IDLE:
+ return 0;
+
+ case STATE_DFU_DOWNLOAD_SYNC:
+ case STATE_DFU_DOWNLOAD_IDLE:
+ case STATE_DFU_MANIFEST_SYNC:
+ case STATE_DFU_UPLOAD_IDLE:
+ case STATE_DFU_DOWNLOAD_BUSY:
+ case STATE_DFU_MANIFEST:
+ dfu_abort(dev, iface);
+ continue;
+
+ case STATE_DFU_ERROR:
+ dfu_clrstatus(dev, iface);
+ continue;
+
+ case STATE_APP_IDLE:
+ dfu_detach(dev, iface, DFU_DETACH_TIMEOUT);
+ continue;
+
+ case STATE_APP_DETACH:
+ case STATE_DFU_MANIFEST_WAIT_RESET:
+ usb_reset(dev);
+ return -1;
+
+ default:
+ return -1;
+ }
+
+ }
+
+ return -1;
+}
+
+
diff --git a/upgrade/dfu.h b/upgrade/dfu.h
new file mode 100644
index 0000000..1594962
--- /dev/null
+++ b/upgrade/dfu.h
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __DFU_H
+#define __DFU_H
+
+#include <stdint.h>
+
+#include <usb.h>
+
+/* DFU states as returned by DFU_GETSTATE and DFU_GETSTATUS request in bState field.
+ * Refer to Section 6.1.2
+ * Refer to Figure A.1 for state diagram
+ */
+#define STATE_APP_IDLE 0x00
+#define STATE_APP_DETACH 0x01
+#define STATE_DFU_IDLE 0x02
+#define STATE_DFU_DOWNLOAD_SYNC 0x03
+#define STATE_DFU_DOWNLOAD_BUSY 0x04
+define STATE_DFU_DOWNLOAD_IDLE 0x05
+#define STATE_DFU_MANIFEST_SYNC 0x06
+#define STATE_DFU_MANIFEST 0x07
+#define STATE_DFU_MANIFEST_WAIT_RESET 0x08
+#define STATE_DFU_UPLOAD_IDLE 0x09
+#define STATE_DFU_ERROR 0x0a
+
+/* DFU status codes as returned by DFU_GETSTATUS request in bStatus field.
+ * Refer to Section 6.1.2 */
+#define DFU_STATUS_OK 0x00
+#define DFU_STATUS_ERROR_TARGET 0x01
+#define DFU_STATUS_ERROR_FILE 0x02
+#define DFU_STATUS_ERROR_WRITE 0x03
+#define DFU_STATUS_ERROR_ERASE 0x04
+#define DFU_STATUS_ERROR_CHECK_ERASED 0x05
+#define DFU_STATUS_ERROR_PROG 0x06
+#define DFU_STATUS_ERROR_VERIFY 0x07
+#define DFU_STATUS_ERROR_ADDRESS 0x08
+#define DFU_STATUS_ERROR_NOTDONE 0x09
+#define DFU_STATUS_ERROR_FIRMWARE 0x0a
+#define DFU_STATUS_ERROR_VENDOR 0x0b
+#define DFU_STATUS_ERROR_USBR 0x0c
+#define DFU_STATUS_ERROR_POR 0x0d
+#define DFU_STATUS_ERROR_UNKNOWN 0x0e
+#define DFU_STATUS_ERROR_STALLEDPKT 0x0f
+
+/* Device status structure returned by DFU_GETSTATUS request.
+ * Refer to Section 6.1.2 */
+typedef struct dfu_status {
+ uint8_t bStatus;
+ uint32_t bwPollTimeout:24;
+ uint8_t bState;
+ uint8_t iString;
+} __attribute__((packed)) dfu_status;
+
+
+int dfu_detach(usb_dev_handle *dev, uint16_t iface, uint16_t wTimeout);
+int dfu_dnload(usb_dev_handle *dev, uint16_t iface,
+ uint16_t wBlockNum, void *data, uint16_t size);
+int dfu_upload(usb_dev_handle *dev, uint16_t iface,
+ uint16_t wBlockNum, void *data, uint16_t size);
+int dfu_getstatus(usb_dev_handle *dev, uint16_t iface, dfu_status *status);
+int dfu_clrstatus(usb_dev_handle *dev, uint16_t iface);
+int dfu_getstate(usb_dev_handle *dev, uint16_t iface);
+int dfu_abort(usb_dev_handle *dev, uint16_t iface);
+
+int dfu_makeidle(usb_dev_handle *dev, uint16_t iface);
+
+
+#endif
+
diff --git a/upgrade/main.c b/upgrade/main.c
new file mode 100644
index 0000000..bdb1b6b
--- /dev/null
+++ b/upgrade/main.c
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdio.h>
+#include <usb.h>
+#include <string.h>
+
+#include "dfu.h"
+#include "stm32mem.h"
+#include "bindata.h"
+
+#define VERSION "1.0"
+
+#define LOAD_ADDRESS 0x8002000
+
+void banner(void)
+{
+ puts("\nBlack Magic Probe -- Firmware Upgrade Utility -- Version " VERSION);
+ puts("Copyright (C) 2011 Black Sphere Technologies Ltd.");
+ puts("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n");
+}
+
+
+struct usb_device * find_dev(void)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ struct usb_dev_handle *handle;
+ char man[40];
+ char prod[40];
+
+ usb_find_busses();
+ usb_find_devices();
+
+ for(bus = usb_get_busses(); bus; bus = bus->next) {
+ for(dev = bus->devices; dev; dev = dev->next) {
+ /* Check for ST Microelectronics vendor ID */
+ if(dev->descriptor.idVendor != 0x483) continue;
+
+ handle = usb_open(dev);
+ usb_get_string_simple(handle, dev->descriptor.iManufacturer, man,
+ sizeof(man));
+ usb_get_string_simple(handle, dev->descriptor.iProduct, prod,
+ sizeof(prod));
+#if 0
+ printf("%s:%s [%04X:%04X] %s : %s\n", bus->dirname, dev->filename,
+ dev->descriptor.idVendor, dev->descriptor.idProduct, man, prod);
+#endif
+ usb_close(handle);
+
+ if((dev->descriptor.idProduct == 0x5740) &&
+ !strcmp(man, "Black Sphere Technologies") &&
+ !strcmp(prod, "Black Magic Probe"))
+ return dev;
+
+ if((dev->descriptor.idProduct == 0xDF11) &&
+ !strcmp(man, "Black Sphere Technologies") &&
+ !strcmp(prod, "Black Magic Probe (Upgrade)"))
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+usb_dev_handle * get_dfu_interface(struct usb_device *dev, uint16_t *interface)
+{
+ int i, j, k;
+ struct usb_config_descriptor *config;
+ struct usb_interface_descriptor *iface;
+
+ usb_dev_handle *handle;
+
+ for(i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ config = &dev->config[i];
+
+ for(j = 0; j < config->bNumInterfaces; j++) {
+ for(k = 0; k < config->interface[j].num_altsetting; k++) {
+ iface = &config->interface[j].altsetting[k];
+ if((iface->bInterfaceClass == 0xFE) &&
+ (iface->bInterfaceSubClass = 0x01)) {
+ handle = usb_open(dev);
+ //usb_set_configuration(handle, i);
+ usb_claim_interface(handle, j);
+ //usb_set_altinterface(handle, k);
+ *interface = j;
+ return handle;
+ }
+ }
+
+ }
+ }
+ return NULL;
+}
+
+int main(void)
+{
+ struct usb_device *dev;
+ usb_dev_handle *handle;
+ uint16_t iface;
+ int state;
+ uint32_t offset;
+
+ banner();
+ usb_init();
+
+retry:
+ if(!(dev = find_dev()) || !(handle = get_dfu_interface(dev, &iface))) {
+ puts("FATAL: No compatible device found!\n");
+ return -1;
+ }
+
+ state = dfu_getstate(handle, iface);
+ if((state < 0) || (state == STATE_APP_IDLE)) {
+ puts("Resetting device in firmware upgrade mode...");
+ dfu_detach(handle, iface, 1000);
+ usb_release_interface(handle, iface);
+ usb_close(handle);
+#ifdef WIN32
+ Sleep(3000);
+#else
+ sleep(1);
+#endif
+ goto retry;
+ }
+ printf("Found device at %s:%s\n", dev->bus->dirname, dev->filename);
+
+ dfu_makeidle(handle, iface);
+
+ for(offset = 0; offset < bindatalen; offset += 1024) {
+ printf("Progress: %d%%\r", (offset*100)/bindatalen);
+ fflush(stdout);
+ stm32_mem_erase(handle, iface, LOAD_ADDRESS + offset);
+ stm32_mem_write(handle, iface, (void*)&bindata[offset], 1024);
+ }
+ stm32_mem_manifest(handle, iface);
+
+ usb_release_interface(handle, iface);
+ usb_close(handle);
+
+ puts("All operations complete!\n");
+
+ return 0;
+}
+
diff --git a/upgrade/stm32mem.c b/upgrade/stm32mem.c
new file mode 100644
index 0000000..10dd744
--- /dev/null
+++ b/upgrade/stm32mem.c
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <usb.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+#include "dfu.h"
+#include "stm32mem.h"
+
+#define STM32_CMD_GETCOMMANDS 0x00
+#define STM32_CMD_SETADDRESSPOINTER 0x21
+#define STM32_CMD_ERASE 0x41
+
+static int stm32_download(usb_dev_handle *dev, uint16_t iface,
+ uint16_t wBlockNum, void *data, int size)
+{
+ dfu_status status;
+ int i;
+
+ if((i = dfu_dnload(dev, iface, wBlockNum, data, size)) < 0) return i;
+ while(1) {
+ if((i = dfu_getstatus(dev, iface, &status)) < 0) return i;
+ switch(status.bState) {
+ case STATE_DFU_DOWNLOAD_BUSY:
+#ifdef WIN32
+ Sleep(status.bwPollTimeout);
+#else
+ usleep(status.bwPollTimeout * 1000);
+#endif
+ break;
+ case STATE_DFU_DOWNLOAD_IDLE:
+ return 0;
+ default:
+ return -1;
+ }
+ }
+}
+
+int stm32_mem_erase(usb_dev_handle *dev, uint16_t iface, uint32_t addr)
+{
+ uint8_t request[5];
+
+ request[0] = STM32_CMD_ERASE;
+ memcpy(request+1, &addr, sizeof(addr));
+
+ return stm32_download(dev, iface, 0, request, sizeof(request));
+}
+
+int stm32_mem_write(usb_dev_handle *dev, uint16_t iface, void *data, int size)
+{
+ return stm32_download(dev, iface, 2, data, size);
+}
+
+int stm32_mem_manifest(usb_dev_handle *dev, uint16_t iface)
+{
+ dfu_status status;
+ int i;
+
+ if((i = dfu_dnload(dev, iface, 0, NULL, 0)) < 0) return i;
+ while(1) {
+ if((i = dfu_getstatus(dev, iface, &status)) < 0) return 0;
+#ifdef WIN32
+ Sleep(status.bwPollTimeout);
+#else
+ usleep(status.bwPollTimeout * 1000);
+#endif
+ switch(status.bState) {
+ case STATE_DFU_MANIFEST:
+ return 0;
+ default:
+ return -1;
+ }
+ }
+}
+
diff --git a/upgrade/stm32mem.h b/upgrade/stm32mem.h
new file mode 100644
index 0000000..34cdfb1
--- /dev/null
+++ b/upgrade/stm32mem.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __STM32MEM_H
+#define __STM32MEM_H
+
+#include <usb.h>
+
+int stm32_mem_erase(usb_dev_handle *dev, uint16_t iface, uint32_t addr);
+int stm32_mem_write(usb_dev_handle *dev, uint16_t iface, void *data, int size);
+int stm32_mem_manifest(usb_dev_handle *dev, uint16_t iface);
+
+#endif
+