diff options
author | Bad Diode <bd@badd10de.dev> | 2021-09-07 16:46:30 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-09-07 16:46:30 +0200 |
commit | e4d111a55e8f1d9b49e67dc98d9d2cdf418d9221 (patch) | |
tree | f7d551fb922d6bde5d27b006e413dc0bf59afab0 | |
parent | 11a95bd16da3ba212ebbd64300c9136cee555bc1 (diff) | |
download | uxnrpi-e4d111a55e8f1d9b49e67dc98d9d2cdf418d9221.tar.gz uxnrpi-e4d111a55e8f1d9b49e67dc98d9d2cdf418d9221.zip |
Add working framebuffer request
Resources:
- https://jsandler18.github.io/extra/prop-channel.html
- https://jsandler18.github.io/extra/mailbox.html
- https://github.com/bztsrc/raspi3-tutorial/tree/master/09_framebuffer
- https://www.youtube.com/watch?v=hSJWbmiQfck
-rw-r--r-- | src/common.h | 105 | ||||
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/ppu.c | 54 |
3 files changed, 160 insertions, 4 deletions
diff --git a/src/common.h b/src/common.h index a6af346..0bd365a 100644 --- a/src/common.h +++ b/src/common.h | |||
@@ -60,11 +60,9 @@ static inline void | |||
60 | gpio_pin_set_func(u8 pin, GpioFunc func) { | 60 | gpio_pin_set_func(u8 pin, GpioFunc func) { |
61 | u8 start = (pin * 3) % 30; | 61 | u8 start = (pin * 3) % 30; |
62 | u8 reg = pin / 10; | 62 | u8 reg = pin / 10; |
63 | |||
64 | u32 selector = GPIO->func_select[reg]; | 63 | u32 selector = GPIO->func_select[reg]; |
65 | selector &= ~(7 << start); | 64 | selector &= ~(7 << start); |
66 | selector |= (func << start); | 65 | selector |= (func << start); |
67 | |||
68 | GPIO->func_select[reg] = selector; | 66 | GPIO->func_select[reg] = selector; |
69 | } | 67 | } |
70 | 68 | ||
@@ -144,4 +142,107 @@ uart_puts(char *s) { | |||
144 | } | 142 | } |
145 | } | 143 | } |
146 | 144 | ||
145 | static inline void | ||
146 | uart_hex(unsigned int d) { | ||
147 | unsigned int n; | ||
148 | uart_puts("0x"); | ||
149 | for(int c = 28; c >= 0; c -= 4) { | ||
150 | n = (d>>c) & 0xF; | ||
151 | n += n> 9 ? 0x37 : 0x30; | ||
152 | uart_putc(n); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // | ||
157 | // VideoCore Mailboxes. | ||
158 | // | ||
159 | |||
160 | typedef struct MboxTagHeader { | ||
161 | u32 id; | ||
162 | u32 buf_size; | ||
163 | u32 code; | ||
164 | } MboxTagHeader; | ||
165 | |||
166 | typedef struct MboxScreenTag { | ||
167 | MboxTagHeader header; | ||
168 | u32 width; | ||
169 | u32 height; | ||
170 | } MboxScreenTag; | ||
171 | |||
172 | typedef struct MboxDepthTag { | ||
173 | MboxTagHeader header; | ||
174 | u32 depth; | ||
175 | } MboxDepthTag; | ||
176 | |||
177 | typedef struct MboxFramebufferTag { | ||
178 | MboxTagHeader header; | ||
179 | u32 fb_addr; | ||
180 | u32 fb_size; | ||
181 | } MboxFramebufferTag; | ||
182 | |||
183 | typedef struct MboxFramebufferRequest { | ||
184 | u32 buf_size; | ||
185 | u32 code; | ||
186 | MboxScreenTag screen_tag; | ||
187 | MboxScreenTag virtual_screen_tag; | ||
188 | MboxDepthTag depth_tag; | ||
189 | MboxFramebufferTag framebuffer_tag; | ||
190 | u32 end_tag; | ||
191 | u8 padding[8]; | ||
192 | } MboxFramebufferRequest; | ||
193 | |||
194 | typedef struct MailboxRegs { | ||
195 | vu32 read; | ||
196 | vu32 reserved[5]; | ||
197 | vu32 status; | ||
198 | vu32 config; | ||
199 | vu32 write; | ||
200 | } MailboxRegs; | ||
201 | |||
202 | #define MBOX ((MailboxRegs *)(MEM_BASE + 0x0000B880)) | ||
203 | |||
204 | typedef enum MboxChannels { | ||
205 | MBOX_CH_POWER = 0, | ||
206 | MBOX_CH_FB = 1, | ||
207 | MBOX_CH_VUART = 2, | ||
208 | MBOX_CH_VCHIQ = 3, | ||
209 | MBOX_CH_LEDS = 4, | ||
210 | MBOX_CH_BTNS = 5, | ||
211 | MBOX_CH_TOUCH = 6, | ||
212 | MBOX_CH_COUNT = 7, | ||
213 | MBOX_CH_PROP = 8, | ||
214 | } MboxChannels; | ||
215 | |||
216 | // Property channel response type. | ||
217 | #define MBOX_REQUEST 0 | ||
218 | #define MBOX_RESPONSE_OK 0x80000000 | ||
219 | #define MBOX_RESPONSE_ERR 0x80000001 | ||
220 | |||
221 | // Mailbox status codes. | ||
222 | #define MBOX_FULL 0x80000000 | ||
223 | #define MBOX_EMPTY 0x40000000 | ||
224 | |||
225 | static inline void | ||
226 | mb_write(u8 channel, void *data) { | ||
227 | while(MBOX->status & MBOX_FULL); | ||
228 | MBOX->write = ((uintptr_t)data & ~0xF) | (channel & 0xF); | ||
229 | } | ||
230 | |||
231 | static inline u32 | ||
232 | mb_read(u8 channel) { | ||
233 | while(true) { | ||
234 | while(MBOX->status & MBOX_EMPTY); | ||
235 | u32 data = MBOX->read; | ||
236 | if ((u8)(data & 0xF) == channel) { | ||
237 | return data & 0xFFFFFFF0; | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | static inline int | ||
243 | mb_call(unsigned char ch, void *msg) { | ||
244 | mb_write(ch, msg); | ||
245 | return mb_read(ch); | ||
246 | } | ||
247 | |||
147 | #endif // COMMON_RPIBM_H | 248 | #endif // COMMON_RPIBM_H |
@@ -1,13 +1,14 @@ | |||
1 | #include "common.h" | 1 | #include "common.h" |
2 | #include "ppu.c" | ||
2 | 3 | ||
3 | void main(void) { | 4 | void main(void) { |
4 | // Initialize uart. | 5 | // Initialize uart. |
5 | uart_init(); | 6 | uart_init(); |
6 | 7 | ||
7 | uart_puts("Hello World!\n"); | 8 | ppu_init(); |
8 | 9 | ||
9 | // Echo input to standard output. | ||
10 | while(1) { | 10 | while(1) { |
11 | // Echo input to standard output. | ||
11 | uart_putc(uart_getc()); | 12 | uart_putc(uart_getc()); |
12 | } | 13 | } |
13 | } | 14 | } |
diff --git a/src/ppu.c b/src/ppu.c new file mode 100644 index 0000000..99574d7 --- /dev/null +++ b/src/ppu.c | |||
@@ -0,0 +1,54 @@ | |||
1 | #include "common.h" | ||
2 | |||
3 | static u32 *framebuffer = 0; | ||
4 | |||
5 | void | ||
6 | ppu_init(void) { | ||
7 | static MboxFramebufferRequest fb_request = { | ||
8 | .buf_size = 96, | ||
9 | .code = MBOX_REQUEST, | ||
10 | .screen_tag = { | ||
11 | .header = { | ||
12 | .id = 0x48003, | ||
13 | .buf_size = 8, | ||
14 | }, | ||
15 | .width = 1024, | ||
16 | .height = 1024, | ||
17 | }, | ||
18 | .virtual_screen_tag = { | ||
19 | .header = { | ||
20 | .id = 0x48004, | ||
21 | .buf_size = 8, | ||
22 | }, | ||
23 | .width = 1024, | ||
24 | .height = 1024, | ||
25 | }, | ||
26 | .depth_tag = { | ||
27 | .header = { | ||
28 | .id = 0x48005, | ||
29 | .buf_size = 4, | ||
30 | }, | ||
31 | .depth = 32, | ||
32 | }, | ||
33 | .framebuffer_tag = { | ||
34 | .header = { | ||
35 | .id = 0x40001, | ||
36 | .buf_size = 8, | ||
37 | }, | ||
38 | .fb_addr = 0, | ||
39 | .fb_size = 0, | ||
40 | } | ||
41 | }; | ||
42 | |||
43 | if (mb_call(MBOX_CH_PROP, &fb_request) | ||
44 | && fb_request.depth_tag.depth == 32 | ||
45 | && fb_request.framebuffer_tag.fb_addr != 0) { | ||
46 | fb_request.framebuffer_tag.fb_addr &= 0x3FFFFFFF; | ||
47 | framebuffer = (u32*)((uintptr_t)fb_request.framebuffer_tag.fb_addr); | ||
48 | for (size_t i = 0; i < 1024 * 100; i++) { | ||
49 | framebuffer[i] = 0xffaa22; // 0xBBGGRR | ||
50 | } | ||
51 | } else { | ||
52 | uart_puts("Unable initialize framebuffer\n"); | ||
53 | } | ||
54 | } | ||