aboutsummaryrefslogtreecommitdiffstats
path: root/src/common.h
blob: a6af346b91301ec647a7ce6c94a21b72e769be00 (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
#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++);
    }
}

#endif // COMMON_RPIBM_H