summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/boards/rockchip.rst15
-rw-r--r--arch/sandbox/configs/hosttools_defconfig1
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Kconfig8
-rw-r--r--scripts/Makefile3
-rw-r--r--scripts/rk-usb-loader.c328
-rw-r--r--scripts/rkimage.c32
-rw-r--r--scripts/rockchip.h35
8 files changed, 392 insertions, 31 deletions
diff --git a/Documentation/boards/rockchip.rst b/Documentation/boards/rockchip.rst
index 55a3956dd4..d52d979cbf 100644
--- a/Documentation/boards/rockchip.rst
+++ b/Documentation/boards/rockchip.rst
@@ -84,3 +84,18 @@ A bootable SD card can be created with:
The barebox image is written to the raw device, so make sure the partitioning
doesn't conflict with the are barebox is written to. Starting the first
partition at offset 8MiB is a safe bet.
+
+USB bootstrapping
+^^^^^^^^^^^^^^^^^
+
+The RK3568 can be bootstrapped via USB for which the rk-usb-loader tool in the barebox
+repository can be used. The tool takes the same images as written on SD cards:
+
+.. code-block:: sh
+
+ ./scripts/rk-usb-loader images/barebox-rk3568-evb.img
+
+Note that the boot order of the RK3568 is not configurable. The SoC will only enter USB
+MaskROM mode when no other bootsource contains a valid bootloader. This means to use USB
+you have to make all other bootsources invalid by removing SD cards and shortcircuiting
+eMMCs. The RK3568 EVB has a pushbutton to disable the eMMC.
diff --git a/arch/sandbox/configs/hosttools_defconfig b/arch/sandbox/configs/hosttools_defconfig
index 7d33853124..0b62b648c7 100644
--- a/arch/sandbox/configs/hosttools_defconfig
+++ b/arch/sandbox/configs/hosttools_defconfig
@@ -4,3 +4,4 @@ CONFIG_ARCH_IMX_USBLOADER=y
CONFIG_MVEBU_HOSTTOOLS=y
CONFIG_OMAP3_USB_LOADER=y
CONFIG_OMAP4_HOSTTOOL_USBBOOT=y
+CONFIG_RK_USB_LOADER=y
diff --git a/scripts/.gitignore b/scripts/.gitignore
index cf645ec746..bc6e5dbc43 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -31,6 +31,7 @@ omap4_usbboot
omap4_usbboot-target
omap3-usb-loader
omap3-usb-loader-target
+rk-usb-loader
mips-relocs
rsatoc
stm32image
diff --git a/scripts/Kconfig b/scripts/Kconfig
index 2bf6f8a264..b633e3011f 100644
--- a/scripts/Kconfig
+++ b/scripts/Kconfig
@@ -102,6 +102,14 @@ config OMAP4_HOSTTOOL_USBBOOT
You need libusb-1.0 to compile this tool.
+config RK_USB_LOADER
+ bool "Rockchip USB loader"
+ depends on ARCH_ROCKCHIP || COMPILE_HOST_TOOLS
+ help
+ Say Y here to build the rockchip usb loader tool.
+
+ You need libusb-1.0 to compile this tool.
+
endmenu
menu "Target Tools"
diff --git a/scripts/Makefile b/scripts/Makefile
index 70f4b1429a..433a301431 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -36,6 +36,9 @@ hostprogs-always-$(CONFIG_OMAP3_USB_LOADER) += omap3-usb-loader
HOSTCFLAGS_omap4_usbboot.o = `pkg-config --cflags libusb-1.0`
HOSTLDLIBS_omap4_usbboot = -lpthread `pkg-config --libs libusb-1.0`
hostprogs-always-$(CONFIG_OMAP4_HOSTTOOL_USBBOOT) += omap4_usbboot
+HOSTCFLAGS_rk-usb-loader.o = `pkg-config --cflags libusb-1.0`
+HOSTLDLIBS_rk-usb-loader = `pkg-config --libs libusb-1.0`
+hostprogs-always-$(CONFIG_RK_USB_LOADER) += rk-usb-loader
userprogs-always-$(CONFIG_BAREBOXENV_TARGET) += bareboxenv-target
userprogs-always-$(CONFIG_KERNEL_INSTALL_TARGET) += kernel-install-target
diff --git a/scripts/rk-usb-loader.c b/scripts/rk-usb-loader.c
new file mode 100644
index 0000000000..9c2367ed28
--- /dev/null
+++ b/scripts/rk-usb-loader.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*
+ * rk-usb-loader: A tool to USB Bootstrap Rockchip SoCs
+ *
+ * This tool bootstraps Rockchip SoCs via USB. It is known to work
+ * on these SoCs:
+ *
+ * - RK3568
+ * - RK3566
+ *
+ * rk-usb-loader takes the barebox images the barebox build process
+ * generates as input. The upload protocol has been taken from the
+ * rkdevelop tool, but it's not a full replacement of that tool.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libusb.h>
+
+#include "common.h"
+#include "common.c"
+#include "rockchip.h"
+
+static void log_error(char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ fprintf(stdout, "[-] ");
+ vfprintf(stdout, fmt, va);
+ va_end(va);
+}
+
+static void log_info(char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ fprintf(stdout, "[+] ");
+ vfprintf(stdout, fmt, va);
+ va_end(va);
+}
+
+static int debug;
+
+static void log_debug(char *fmt, ...)
+{
+ va_list va;
+
+ if (!debug)
+ return;
+
+ va_start(va, fmt);
+ fprintf(stdout, "[D] ");
+ vfprintf(stdout, fmt, va);
+ va_end(va);
+}
+
+static libusb_device_handle *rk_usb_open(libusb_context *ctx, uint16_t vendor, uint16_t product)
+{
+ libusb_device **devlist;
+ libusb_device_handle *handle;
+ struct libusb_device_descriptor desc;
+ ssize_t count, i;
+ int ret;
+
+ log_info("scanning for USB device matching %04hx:%04hx...\n",
+ vendor, product);
+
+ while (1) {
+ if ((count = libusb_get_device_list(ctx, &devlist)) < 0) {
+ log_error("failed to gather USB device list: %s\n",
+ libusb_error_name(count));
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++) {
+ ret = libusb_get_device_descriptor(devlist[i], &desc);
+ if (ret < 0) {
+ log_error("failed to get USB device descriptor: %s\n",
+ libusb_error_name(ret));
+ libusb_free_device_list(devlist, 1);
+ return NULL;
+ }
+
+ if (desc.idVendor != vendor)
+ continue;
+
+ if (product) {
+ if (desc.idProduct != product)
+ continue;
+ goto found;
+ }
+ }
+
+ libusb_free_device_list(devlist, 1);
+
+ /* nothing found yet. have a 10ms nap */
+ usleep(10000);
+ }
+found:
+
+ ret = libusb_open(devlist[i], &handle);
+ if (ret < 0) {
+ log_error("failed to open USB device %04hx:%04hx: %s\n",
+ vendor, product, libusb_error_name(ret));
+ libusb_free_device_list(devlist, 1);
+ return NULL;
+ }
+
+ ret = libusb_claim_interface(handle, 0);
+ if (ret) {
+ printf("Claim failed\n");
+ return NULL;
+ }
+
+ log_info("successfully opened %04hx:%04hx\n", vendor, product);
+
+ return handle;
+}
+
+#define poly16_CCITT 0x1021 /* crc-ccitt mask */
+
+static uint16_t crc_calculate(uint16_t crc, unsigned char ch)
+{
+ unsigned int i;
+
+ for (i = 0x80; i != 0; i >>= 1) {
+ if (crc & 0x8000) {
+ crc <<= 1;
+ crc ^= poly16_CCITT;
+ } else {
+ crc <<= 1;
+ }
+
+ if (ch & i)
+ crc ^= poly16_CCITT;
+ }
+ return crc;
+}
+
+static uint16_t crc_ccitt(unsigned char *p, int n)
+{
+ uint16_t crc = 0xffff;
+
+ while (n--) {
+ crc = crc_calculate(crc, *p);
+ p++;
+ }
+
+ return crc;
+}
+
+static int upload(libusb_device_handle *dev, unsigned int dwRequest, void *buf, int n_bytes)
+{
+ uint16_t crc;
+ uint8_t *data;
+ int sent = 0, ret;
+
+ data = calloc(n_bytes + 5, 1);
+ memcpy(data, buf, n_bytes);
+
+ crc = crc_ccitt(data, n_bytes);
+ data[n_bytes] = (crc & 0xff00) >> 8;
+ data[n_bytes + 1] = crc & 0x00ff;
+ n_bytes += 2;
+
+ while (sent < n_bytes) {
+ int now;
+
+ if (n_bytes - sent > 4096)
+ now = 4096;
+ else
+ now = n_bytes - sent;
+
+ ret = libusb_control_transfer(dev, 0x40, 0xC, 0, dwRequest,
+ data + sent, now, 0);
+ if (ret != now) {
+ log_error("DeviceRequest 0x%x failed, err=%d",
+ dwRequest, ret);
+
+ ret = -EIO;
+ goto err;
+ }
+ sent += now;
+ }
+
+ ret = 0;
+err:
+ free(data);
+
+ return ret;
+}
+
+static int upload_image(const char *filename)
+{
+ libusb_context *ctx;
+ libusb_device_handle *dev;
+ int ret;
+ void *buf;
+ struct newidb *hdr;
+ int i, n_files;
+ size_t size;
+
+ buf = read_file(filename, &size);
+ if (!buf)
+ exit(1);
+
+ hdr = buf;
+
+ if (hdr->magic != NEWIDB_MAGIC) {
+ log_error("%s has invalid magic 0x%08x ( != 0x%08x )\n", filename,
+ hdr->magic, NEWIDB_MAGIC);
+ exit(1);
+ }
+
+ ret = libusb_init(&ctx);
+ if (ret < 0) {
+ log_error("failed to initialize libusb context: %s\n",
+ libusb_error_name(ret));
+ return ret;
+ }
+
+ dev = rk_usb_open(ctx, 0x2207, 0x350a);
+ if (!dev) {
+ libusb_exit(ctx);
+ return 1;
+ }
+
+ n_files = hdr->n_files >> 16;
+
+ if (n_files > 2) {
+ /*
+ * This tool is designed for barebox images generated with rkimage.
+ * These have one blob containing the SDRAM setup sent with the
+ * CODE471_OPTION and one blob containing the barebox image sent with
+ * the CODE472_OPTION.
+ */
+ log_error("Invalid image with %d blobs\n", n_files);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < n_files; i++) {
+ struct newidb_entry *entry = &hdr->entries[i];
+ int foffset, fsize, wIndex;
+
+ if (i)
+ wIndex = 0x472;
+ else
+ wIndex = 0x471;
+
+ log_info("Uploading %d/%d\n", i + 1, n_files);
+
+ foffset = (entry->sector & 0xffff) * SECTOR_SIZE;
+ fsize = (entry->sector >> 16) * SECTOR_SIZE;
+
+ log_debug("image starting at offset 0x%08x, size 0x%08x\n", foffset, fsize);
+
+ ret = upload(dev, wIndex, buf + foffset, fsize);
+ if (ret)
+ goto err;
+ }
+
+ ret = 0;
+err:
+ libusb_close(dev);
+ libusb_exit(ctx);
+
+ return ret;
+}
+
+static void usage(const char *prgname)
+{
+ printf(
+"Usage: %s [OPTIONS] <IMAGE>\n"
+"\n"
+"Options:\n"
+" -d Enable debugging output\n"
+" -h This help\n",
+ prgname);
+}
+
+static struct option cbootcmd[] = {
+ {"debug", 0, NULL, 'd'},
+ {"help", 0, NULL, 'h'},
+ {0, 0, 0, 0},
+};
+
+int main(int argc, char **argv)
+{
+ int opt, ret;
+ const char *filename;
+
+ while ((opt = getopt_long(argc, argv, "hd", cbootcmd, NULL)) > 0) {
+ switch (opt) {
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ case 'd':
+ debug = 1;
+ break;
+ }
+ }
+
+ if (argc == optind) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ filename = argv[optind];
+
+ ret = upload_image(filename);
+ if (ret)
+ exit(1);
+
+ exit(0);
+}
diff --git a/scripts/rkimage.c b/scripts/rkimage.c
index 21a2838146..6e68d508ac 100644
--- a/scripts/rkimage.c
+++ b/scripts/rkimage.c
@@ -15,6 +15,7 @@
#include "common.h"
#include "common.c"
+#include "rockchip.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
@@ -37,37 +38,6 @@ static void sha512(const void *buf, int len, void *out)
SHA512_Final(out, &sha512);
}
-#define NEWIDB_MAGIC 0x534e4b52 /* 'RKNS' */
-
-struct newidb_entry {
- uint32_t sector;
- uint32_t unknown_ffffffff;
- uint32_t unknown1;
- uint32_t image_number;
- unsigned char unknown2[8];
- unsigned char hash[64];
-};
-
-struct newidb {
- uint32_t magic;
- unsigned char unknown1[4];
- uint32_t n_files;
- uint32_t hashtype;
- unsigned char unknown2[8];
- unsigned char unknown3[8];
- unsigned char unknown4[88];
- struct newidb_entry entries[4];
- unsigned char unknown5[40];
- unsigned char unknown6[512];
- unsigned char unknown7[16];
- unsigned char unknown8[32];
- unsigned char unknown9[464];
- unsigned char hash[512];
-};
-
-#define SECTOR_SIZE 512
-#define PAGE_SIZE 2048
-
typedef enum {
HASH_TYPE_SHA256 = 1,
HASH_TYPE_SHA512 = 2,
diff --git a/scripts/rockchip.h b/scripts/rockchip.h
new file mode 100644
index 0000000000..8cc14f8f2f
--- /dev/null
+++ b/scripts/rockchip.h
@@ -0,0 +1,35 @@
+#ifndef __ROCKCHIP_H
+#define __ROCKCHIP_H
+
+#define NEWIDB_MAGIC 0x534e4b52 /* 'RKNS' */
+
+struct newidb_entry {
+ uint32_t sector;
+ uint32_t unknown_ffffffff;
+ uint32_t unknown1;
+ uint32_t image_number;
+ unsigned char unknown2[8];
+ unsigned char hash[64];
+};
+
+struct newidb {
+ uint32_t magic;
+ unsigned char unknown1[4];
+ uint32_t n_files;
+ uint32_t hashtype;
+ unsigned char unknown2[8];
+ unsigned char unknown3[8];
+ unsigned char unknown4[88];
+ struct newidb_entry entries[4];
+ unsigned char unknown5[40];
+ unsigned char unknown6[512];
+ unsigned char unknown7[16];
+ unsigned char unknown8[32];
+ unsigned char unknown9[464];
+ unsigned char hash[512];
+};
+
+#define SECTOR_SIZE 512
+#define PAGE_SIZE 2048
+
+#endif /* __ROCKCHIP_H */