aboutsummaryrefslogtreecommitdiffstats
path: root/src/common.h
blob: 1b21573f0c24a461a4394e8ee8f6d7ab09fe2e33 (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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#ifndef COMMON_RPIBM_H
#define COMMON_RPIBM_H

// Header definitions for memory mapped IO and common utilities.

#include "shorthand.h"

//
// Utils.
//

// Wait for N processor cycles before returning. Implemented in start.s.
void delay(u64 ticks);

// Clear N bytes at the given address. Implemented in start.s.
void memzero(u64 src, u32 n);

#define MEM_BASE 0x3F000000

//
// GPIO Registers.
//

typedef struct GpioPinData {
    vu32 reserved;
    vu32 data[2];
} GpioPinData;

typedef struct GpioRegs {
    vu32 func_select[6];
    GpioPinData output_set;
    GpioPinData output_clear;
    GpioPinData level;
    GpioPinData ev_detect_status;
    GpioPinData re_detect_enable;
    GpioPinData fe_detect_enable;
    GpioPinData hi_detect_enable;
    GpioPinData lo_detect_enable;
    GpioPinData async_re_detect;
    GpioPinData async_fe_detect;
    vu32 reserved;
    vu32 pupd_enable;
    vu32 pupd_enable_clocks[2];
} GpioRegs;

typedef enum GpioFunc {
    GPIO_INPUT  = 0,
    GPIO_OUTPUT = 1,
    GPIO_ALT0   = 4,
    GPIO_ALT1   = 5,
    GPIO_ALT2   = 6,
    GPIO_ALT3   = 7,
    GPIO_ALT4   = 3,
    GPIO_ALT5   = 2,
} GpioFunc;

#define GPIO ((GpioRegs *)(MEM_BASE + 0x00200000))

static inline void
gpio_pin_set_func(u8 pin, GpioFunc func) {
    u8 start = (pin * 3) % 30;
    u8 reg = pin / 10;
    u32 selector = GPIO->func_select[reg];
    selector &= ~(7 << start);
    selector |= (func << start);
    GPIO->func_select[reg] = selector;
}

static inline void
gpio_pin_enable(u8 pin) {
    GPIO->pupd_enable = 0;
    delay(150);
    GPIO->pupd_enable_clocks[pin / 32] = 1 << (pin % 32);
    delay(150);
    GPIO->pupd_enable = 0;
    GPIO->pupd_enable_clocks[pin / 32] = 0;
}

//
// AUX Registers.
//

typedef struct AuxRegs {
    vu32 irq_status;
    vu32 enables;
    vu32 reserved[14];
    vu32 mu_io;
    vu32 mu_ier;
    vu32 mu_iir;
    vu32 mu_lcr;
    vu32 mu_mcr;
    vu32 mu_lsr;
    vu32 mu_msr;
    vu32 mu_scratch;
    vu32 mu_control;
    vu32 mu_status;
    vu32 mu_baud_rate;
} AuxRegs;

#define AUX ((AuxRegs *)(MEM_BASE + 0x00215000))

static inline void
uart_init() {
    gpio_pin_set_func(14, GPIO_ALT5);
    gpio_pin_set_func(15, GPIO_ALT5);
    gpio_pin_enable(14);
    gpio_pin_enable(15);

    AUX->enables = 1;
    AUX->mu_control = 0;
    AUX->mu_ier = 0;
    AUX->mu_lcr = 3;
    AUX->mu_mcr = 0;

    AUX->mu_baud_rate = 270; // RPI3: 115200 @ 250 MHz
    // AUX->mu_baud_rate = 541; // RPI4: 115200 @ 500 MHz
    AUX->mu_control = 3;
    return;
}

static inline void
uart_putc(char c) {
    while(!(AUX->mu_lsr & (1 << 5)));
    AUX->mu_io = c;
    return;
}

static inline char
uart_getc() {
    while(!(AUX->mu_lsr & 1));
    u8 c = AUX->mu_io & 0xFF;
    return c == '\r' ? '\n' : c;
}

static inline void
uart_puts(char *s) {
    while(*s) {
        if(*s == '\n') {
            uart_putc('\r');
        }
        uart_putc(*s++);
    }
}

static inline void
uart_hex(unsigned int d) {
    unsigned int n;
    uart_puts("0x");
    for(int c = 28; c >= 0; c -= 4) {
        n = (d>>c) & 0xF;
        n += n> 9 ? 0x37 : 0x30;
        uart_putc(n);
    }
}

//
// VideoCore Mailboxes.
//

typedef struct MboxTagHeader {
    u32 id;
    u32 buf_size;
    u32 code;
} MboxTagHeader;

typedef struct MboxScreenTag {
    MboxTagHeader header;
    u32 width;
    u32 height;
} MboxScreenTag;

typedef struct MboxDepthTag {
    MboxTagHeader header;
    u32 depth;
} MboxDepthTag;

typedef struct MboxFramebufferTag {
    MboxTagHeader header;
    u32 fb_addr;
    u32 fb_size;
} MboxFramebufferTag;

typedef struct MboxFramebufferRequest {
    u32 buf_size;
    u32 code;
    MboxScreenTag screen_tag;
    MboxScreenTag virtual_screen_tag;
    MboxDepthTag depth_tag;
    MboxFramebufferTag framebuffer_tag;
    u32 end_tag;
    u8 padding[8];
} MboxFramebufferRequest;

typedef struct MailboxRegs {
    vu32 read;
    vu32 reserved[5];
    vu32 status;
    vu32 config;
    vu32 write;
} MailboxRegs;

#define MBOX ((MailboxRegs *)(MEM_BASE + 0x0000B880))

typedef enum MboxChannels {
    MBOX_CH_POWER = 0,
    MBOX_CH_FB    = 1,
    MBOX_CH_VUART = 2,
    MBOX_CH_VCHIQ = 3,
    MBOX_CH_LEDS  = 4,
    MBOX_CH_BTNS  = 5,
    MBOX_CH_TOUCH = 6,
    MBOX_CH_COUNT = 7,
    MBOX_CH_PROP  = 8,
} MboxChannels;

// Property channel response type.
#define MBOX_REQUEST      0
#define MBOX_RESPONSE_OK  0x80000000
#define MBOX_RESPONSE_ERR 0x80000001

// Mailbox status codes.
#define MBOX_FULL  0x80000000
#define MBOX_EMPTY 0x40000000

static inline void
mb_write(u8 channel, void *data) {
    while(MBOX->status & MBOX_FULL);
    MBOX->write = ((uintptr_t)data & ~0xF) | (channel & 0xF);
}

static inline u32
mb_read(u8 channel) {
    while(true) {
        while(MBOX->status & MBOX_EMPTY);
        u32 data = MBOX->read;
        if ((u8)(data & 0xF) == channel) {
            return data & 0xFFFFFFF0;
        }
    }
}

static inline int
mb_call(unsigned char ch, void *msg) {
    mb_write(ch, msg);
    return mb_read(ch);
}

void *
memcpy(void *dest, const void *src, u32 n) {
    u8 *from = (u8*)src;
    u8 *to = (u8*)dest;
    for (size_t i = 0; i < n; i++) {
        to[i] = from[i];
    }
    return dest;
}

#endif // COMMON_RPIBM_H