aboutsummaryrefslogtreecommitdiffstats
path: root/lib/pico-sdk/boot/picoboot.h
blob: 8645d52d738dbf5a11c1c474c94ce93edad6b5d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 * 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_headers boot_picoboot_headers
*
* \brief Header file for the PICOBOOT USB interface exposed by an RP2xxx chip in BOOTSEL mode
*/

#include "picoboot_constants.h"

#define PICOBOOT_MAGIC 0x431fd10bu

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

// size 0 OUT - un-stall 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 = 0x5, // either RAM or FLASH (does no erase)
    PC_EXIT_XIP = 0x6,
    PC_ENTER_CMD_XIP = 0x7,
    PC_EXEC = 0x8,
    PC_VECTORIZE_FLASH = 0x9,
    // RP2350 only below here
    PC_REBOOT2 = 0xa,
    PC_GET_INFO = 0x8b,
    PC_OTP_READ = 0x8c,
    PC_OTP_WRITE = 0xd,
    //PC_EXEC2 = 0xe, // currently unused
};

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,
    PICOBOOT_INVALID_STATE = 9,
    PICOBOOT_NOT_PERMITTED = 10,
    PICOBOOT_INVALID_ARG = 11,
    PICOBOOT_BUFFER_TOO_SMALL = 12,
    PICOBOOT_PRECONDITION_NOT_MET = 13,
    PICOBOOT_MODIFIED_DATA = 14,
    PICOBOOT_INVALID_DATA = 15,
    PICOBOOT_NOT_FOUND = 16,
    PICOBOOT_UNSUPPORTED_MODIFICATION = 17,
};

struct __packed picoboot_reboot_cmd {
    uint32_t dPC; // 0 means reset into regular boot path
    uint32_t dSP;
    uint32_t dDelayMS;
};


// note this (with pc_sp) union member has the same layout as picoboot_reboot_cmd except with extra dFlags
struct __packed picoboot_reboot2_cmd {
    uint32_t dFlags;
    uint32_t dDelayMS;
    uint32_t dParam0;
    uint32_t dParam1;
};

// 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;
};

struct __packed picoboot_exec2_cmd {
    uint32_t image_base;
    uint32_t image_size;
    uint32_t workarea_base;
    uint32_t workarea_size;
};

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

struct __packed picoboot_exclusive_cmd {
    uint8_t bExclusive;
};

struct __packed picoboot_otp_cmd {
    uint16_t wRow; // OTP row
    uint16_t wRowCount; // number of rows to transfer
    uint8_t bEcc; // use error correction (16 bit per register vs 24 (stored as 32) bit raw)
};


struct __packed picoboot_get_info_cmd {
    uint8_t bType;
    uint8_t bParam;
    uint16_t wParam;
    uint32_t dParams[3];
};

// 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;
        struct picoboot_reboot2_cmd reboot2_cmd;
        struct picoboot_otp_cmd otp_cmd;
        struct picoboot_get_info_cmd get_info_cmd;
        struct picoboot_exec2_cmd exec2_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