Skip to content

Commit

Permalink
rp2040: add make flash support
Browse files Browse the repository at this point in the history
This adds `make flash` support for the rp2040 target. Flashing is
performed using a custom `rp2040_flash` tool that uses the PICOBOOT
protocol. Root is not required.

The user specifies the serial device of the rp2040 they wish to flash as
the device. This device is reset into bootsel mode and `rp2040_flash`
is invoked on the original USB device path.

If the device is already in bootloader mode, the user can specify
'first' as `FLASH_DEVICE` which will simply invoke `rp2040_flash` with
no bus/address options.

Signed-off-by: Lasse Dalegaard <dalegaard@gmail.com>
  • Loading branch information
dalegaard authored and KevinOConnor committed Jan 6, 2022
1 parent 8a3727e commit 7c0559c
Show file tree
Hide file tree
Showing 10 changed files with 1,124 additions and 7 deletions.
1 change: 1 addition & 0 deletions lib/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ bossac/bin/
bossac/obj/
hidflash/hid-flash
hub-ctrl/hub-ctrl
rp2040_flash/rp2040_flash
5 changes: 5 additions & 0 deletions lib/README
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ version 1.2.0 (bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7). It has been
modified so that it can build outside of the pico sdk. See
rp2040.patch for the modifications.

The rp2040_flash directory contains a light-weight bootsel flash tool.
It uses C part of the the `picoboot_connection` directory found in:
https://github.com/raspberrypi/picotool.git
version v1.1.0 (55fd880c3dc029b961fc1a0967a6cfdc0af02721).

The hub-ctrl directory contains code from:
https://github.com/codazoda/hub-ctrl.c/
revision 42095e522859059e8a5f4ec05c1e3def01a870a9.
Expand Down
124 changes: 124 additions & 0 deletions lib/rp2040/boot/picoboot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef _BOOT_PICOBOOT_H
#define _BOOT_PICOBOOT_H

#include <stdint.h>
#include <stdbool.h>
#include <assert.h>

#ifndef NO_PICO_PLATFORM
#include "pico/platform.h"
#endif

/** \file picoboot.h
* \defgroup boot_picoboot boot_picoboot
*
* Header file for the PICOBOOT USB interface exposed by an RP2040 in BOOTSEL mode.
*/

#define PICOBOOT_MAGIC 0x431fd10bu

// --------------------------------------------
// CONTROL REQUESTS FOR THE PICOBOOT INTERFACE
// --------------------------------------------

// size 0 OUT - unstall EPs and reset
#define PICOBOOT_IF_RESET 0x41

// size 16 IN - return the status of the last command
#define PICOBOOT_IF_CMD_STATUS 0x42

// --------------------------------------------------
// COMMAND REQUESTS SENT TO THE PICOBOOT OUT ENDPOINT
// --------------------------------------------------
//
// picoboot_cmd structure of size 32 is sent to OUT endpoint
// transfer_length bytes are transferred via IN/OUT
// device responds on success with 0 length ACK packet set via OUT/IN
// device may stall the transferring endpoint in case of error

enum picoboot_cmd_id {
PC_EXCLUSIVE_ACCESS = 0x1,
PC_REBOOT = 0x2,
PC_FLASH_ERASE = 0x3,
PC_READ = 0x84, // either RAM or FLASH
PC_WRITE = 5, // either RAM or FLASH (does no erase)
PC_EXIT_XIP = 0x6,
PC_ENTER_CMD_XIP = 0x7,
PC_EXEC = 0x8,
PC_VECTORIZE_FLASH = 0x9
};

enum picoboot_status {
PICOBOOT_OK = 0,
PICOBOOT_UNKNOWN_CMD = 1,
PICOBOOT_INVALID_CMD_LENGTH = 2,
PICOBOOT_INVALID_TRANSFER_LENGTH = 3,
PICOBOOT_INVALID_ADDRESS = 4,
PICOBOOT_BAD_ALIGNMENT = 5,
PICOBOOT_INTERLEAVED_WRITE = 6,
PICOBOOT_REBOOTING = 7,
PICOBOOT_UNKNOWN_ERROR = 8,
};

struct __packed picoboot_reboot_cmd {
uint32_t dPC; // 0 means reset into bootrom
uint32_t dSP;
uint32_t dDelayMS;
};

// used for EXEC, VECTORIZE_FLASH
struct __packed picoboot_address_only_cmd {
uint32_t dAddr;
};

// used for READ, WRITE, FLASH_ERASE
struct __packed picoboot_range_cmd {
uint32_t dAddr;
uint32_t dSize;
};

enum picoboot_exclusive_type {
NOT_EXCLUSIVE = 0,
EXCLUSIVE,
EXCLUSIVE_AND_EJECT
};

struct __packed picoboot_exclusive_cmd {
uint8_t bExclusive;
};

// little endian
struct __packed __aligned(4) picoboot_cmd {
uint32_t dMagic;
uint32_t dToken; // an identifier for this token to correlate with a status response
uint8_t bCmdId; // top bit set for IN
uint8_t bCmdSize; // bytes of actual data in the arg part of this structure
uint16_t _unused;
uint32_t dTransferLength; // length of IN/OUT transfer (or 0) if none
union {
uint8_t args[16];
struct picoboot_reboot_cmd reboot_cmd;
struct picoboot_range_cmd range_cmd;
struct picoboot_address_only_cmd address_only_cmd;
struct picoboot_exclusive_cmd exclusive_cmd;
};
};

static_assert(32 == sizeof(struct picoboot_cmd), "picoboot_cmd must be 32 bytes big");

struct __packed __aligned(4) picoboot_cmd_status {
uint32_t dToken;
uint32_t dStatusCode;
uint8_t bCmdId;
uint8_t bInProgress;
uint8_t _pad[6];
};

static_assert(16 == sizeof(struct picoboot_cmd_status), "picoboot_cmd_status must be 16 bytes big");
#endif
139 changes: 139 additions & 0 deletions lib/rp2040/pico/platform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef _PICO_PLATFORM_H_
#define _PICO_PLATFORM_H_

#include "hardware/platform_defs.h"
#include <stddef.h>

#ifdef __unix__

#include <sys/cdefs.h>

#endif

#ifdef __cplusplus
extern "C" {
#endif

#define __not_in_flash(grup)
#define __not_in_flash_func(func) func
#define __no_inline_not_in_flash_func(func)
#define __in_flash(group)
#define __scratch_x(group)
#define __scratch_y(group)

#define __packed_aligned
#define __packed

#define __time_critical_func(x) x
#define __after_data(group)

//int running_on_fpga() { return false; }
extern void tight_loop_contents();

#ifndef __STRING
#define __STRING(x) #x
#endif

#ifndef _MSC_VER
#ifndef __noreturn
#define __noreturn __attribute((noreturn))
#endif

#ifndef __unused
#define __unused __attribute__((unused))
#endif

#ifndef __noinline
#define __noinline __attribute__((noinline))
#endif

#ifndef __aligned
#define __aligned(x) __attribute__((aligned(x)))
#endif

#define PICO_WEAK_FUNCTION_DEF(x) _Pragma(__STRING(weak x))
#define PICO_WEAK_FUNCTION_IMPL_NAME(x) x

#else
#ifndef __noreturn
#define __noreturn __declspec(noreturn)
#endif

#ifndef __unused
#define __unused
#endif

#ifndef __noinline
#define __noinline __declspec(noinline)
#endif

#ifndef __aligned
#define __aligned(x) __declspec(align(x))
#endif

#ifndef __CONCAT
#define __CONCAT(x,y) x ## y
#endif

#define __thread __declspec( thread )

#define PICO_WEAK_FUNCTION_DEF(x) __pragma(comment(linker, __STRING(/alternatename:_##x=_##x##__weak)));
#define PICO_WEAK_FUNCTION_IMPL_NAME(x) x ## __weak

static __noreturn void __builtin_unreachable() {
}

#include <intrin.h>
#define __builtin_clz __lzcnt
#endif

#ifndef count_of
#define count_of(a) (sizeof(a)/sizeof((a)[0]))
#endif

#ifndef MAX
#define MAX(a, b) ((a)>(b)?(a):(b))
#endif

#ifndef MIN
#define MIN(a, b) ((b)>(a)?(a):(b))
#endif

// abort in our case
void __noreturn __breakpoint();

void __noreturn panic_unsupported();

void __noreturn panic(const char *fmt, ...);

// arggggghhhh there is a weak function called sem_init used by SDL
#define sem_init sem_init_alternative

extern uint32_t host_safe_hw_ptr_impl(uintptr_t x);
// return a 32 bit handle for a raw ptr; DMA chaining for example embeds pointers in 32 bit values
// which of course does not work if we're running the code natively on a 64 bit platforms. Therefore
// we provide this macro which allows that code to provide a 64->32 bit mapping in host mode
#define host_safe_hw_ptr(x) host_safe_hw_ptr_impl((uintptr_t)(x))
void *decode_host_safe_hw_ptr(uint32_t ptr);

#define __fast_mul(a,b) ((a)*(b))

typedef unsigned int uint;

static inline int32_t __mul_instruction(int32_t a,int32_t b)
{
return a*b;
}

static inline void __compiler_memory_barrier(void) {
}
#ifdef __cplusplus
}
#endif
#endif
20 changes: 20 additions & 0 deletions lib/rp2040_flash/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
CC=gcc
CFLAGS=-c -Wall -ggdb
LDFALGS=
SOURCES=main.c picoboot_connection.c
OBJECTS=$(SOURCES:.c=.o)
LIBS=`pkg-config libusb-1.0 --libs`
INCLUDE_DIRS+=-I../rp2040/ `pkg-config libusb-1.0 --cflags`

EXECUTABLE=rp2040_flash

all: $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@

.c.o:
$(CC) $(CFLAGS) $(INCLUDE_DIRS) $< -o $@

clean:
rm -f $(OBJECTS) $(EXECUTABLE)

0 comments on commit 7c0559c

Please sign in to comment.