display works sortof
[rpikern] / src / rpi.c
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include "rpi.h"
4 #include "sysctl.h"
5 #include "asm.h"
6 #include "serial.h"
7 #include "debug.h"
8
9 #define IOREG(offs)             (*(volatile uint32_t*)(rpi_iobase | offs))
10
11 /* System timer */
12 #define STM_CTL_REG             IOREG(0x3000)
13 #define STM_STAT_REG    STM_CTL_REG
14 #define STM_LCNT_REG    IOREG(0x3004)
15 #define STM_HCNT_REG    IOREG(0x3008)
16 #define STM_CMP0_REG    IOREG(0x300c)
17 #define STM_CMP1_REG    IOREG(0x3010)
18 #define STM_CMP2_REG    IOREG(0x3014)
19 #define STM_CMP3_REG    IOREG(0x3018)
20
21 #define STMCTL_M0               1
22 #define STMCTL_M1               2
23 #define STMCTL_M2               4
24 #define STMCTL_M3               8
25
26 /* TIMER */
27 #define TM_LOAD_REG             IOREG(0xb400)
28 #define TM_VALUE_REG    IOREG(0xb404)
29 #define TM_CTL_REG              IOREG(0xb408)
30 #define TM_ICLR_REG             IOREG(0xb40c)
31 #define TM_IRAW_REG             IOREG(0xb410)
32 #define TM_IMSK_REG             IOREG(0xb414)
33 #define TM_RELOAD_REG   IOREG(0xb418)
34 #define TM_PREDIV_REG   IOREG(0xb41c)
35 #define TM_COUNT_REG    IOREG(0xb420)
36
37 #define TMCTL_23BIT             0x000002
38 #define TMCTL_DIV16             0x000004
39 #define TMCTL_DIV256    0x000008
40 #define TMCTL_DIV1              0x00000c
41 #define TMCTL_IEN               0x000020
42 #define TMCTL_EN                0x000080
43 #define TMCTL_DBGHALT   0x000100
44 #define TMCTL_CNTEN             0x000200
45
46 #define TMCTL_PRESCALER(x)      (((uint32_t)(x) & 0xff) << 16)
47
48 /* watchdog */
49 #define PM_RSTC_REG             IOREG(0x10001c)
50 #define PM_WDOG_REG             IOREG(0x100024)
51
52 #define PM_PASSWD                       0x5a000000
53 #define PMRSTC_WRCFG_FULL_RESET 0x00000020
54 #define PMRSTC_WRCFG_CLEAR              0xffffffcf
55
56 /* MAILBOX */
57 #define MBOX_READ_REG   IOREG(0xb880)
58 #define MBOX_POLL_REG   IOREG(0xb890)
59 #define MBOX_SENDER_REG IOREG(0xb894)
60 #define MBOX_STATUS_REG IOREG(0xb898)
61 #define MBOX_CFG_REG    IOREG(0xb89c)
62 #define MBOX_WRITE_REG  IOREG(0xb8a0)
63
64 /* the full bit is set when there's no space to append messages */
65 #define MBOX_STAT_FULL  0x80000000
66 /* the empty bit is set when there are no pending messages to be read */
67 #define MBOX_STAT_EMPTY 0x40000000
68
69 static int detect(void);
70
71 int rpi_model;
72 uint32_t rpi_iobase;
73 uint32_t rpi_mem_base, rpi_mem_size, rpi_vmem_base, rpi_vmem_size;
74
75
76 /* needs to by 16-byte aligned, because the address we send over the mailbox
77  * interface, will have its 4 least significant bits masked off and taken over
78  * by the mailbox id
79  */
80 static char propbuf[256] __attribute__((aligned(16)));
81 static struct rpi_prop *wrprop, *rdprop;
82
83
84 void rpi_init(void)
85 {
86         struct rpi_prop *prop;
87
88         if((rpi_model = detect()) == -1) {
89                 for(;;) halt_cpu();
90         }
91
92         init_serial(115200);
93
94         /* The model detected by detect is not accurate, get the correct board model
95          * through the mailbox property interface if possible.
96          * Also, detect the amount of CPU and GPU memory available.
97          */
98
99         rpi_prop(RPI_TAG_GETREV);
100         rpi_prop(RPI_TAG_GETRAM);
101         rpi_prop(RPI_TAG_GETVRAM);
102         if(rpi_prop_send() != -1) {
103                 //hexdump(propbuf, sizeof propbuf);
104
105                 while((prop = rpi_prop_next())) {
106                         switch(prop->id) {
107                         case RPI_TAG_GETREV:
108                                 printf("board revision: %x\n", prop->data[0]);
109                                 /* TODO: guess rpi model based on board revision */
110                                 break;
111
112                         case RPI_TAG_GETRAM:
113                                 rpi_mem_base = prop->data[0];
114                                 rpi_mem_size = prop->data[1];
115                                 break;
116
117                         case RPI_TAG_GETVRAM:
118                                 rpi_vmem_base = prop->data[0];
119                                 rpi_vmem_size = prop->data[1];
120                                 break;
121
122                         default:
123                                 break;
124                         }
125                 }
126         }
127 }
128
129 static int detect(void)
130 {
131         int i, j;
132         uint32_t tm0, tm1;
133         static uint32_t base[] = {0x20000000, 0x3f000000, 0xfe000000};
134
135         for(i=0; i<3; i++) {
136                 rpi_iobase = base[i];
137                 tm0 = STM_LCNT_REG;
138                 for(j=0; j<256; j++) {
139                         tm1 = STM_LCNT_REG;
140                 }
141                 if(tm0 != tm1) {
142                         return i + 1;
143                 }
144         }
145         return -1;
146 }
147
148 void rpi_reboot(void)
149 {
150         mem_barrier();
151         PM_WDOG_REG = PM_PASSWD | 1;
152         PM_RSTC_REG = PM_PASSWD | (PM_RSTC_REG & PMRSTC_WRCFG_CLEAR) | PMRSTC_WRCFG_FULL_RESET;
153         for(;;) halt_cpu();
154 }
155
156 void rpi_mbox_send(int chan, uint32_t msg)
157 {
158         mem_barrier();
159         while(MBOX_STATUS_REG & MBOX_STAT_FULL);
160         MBOX_WRITE_REG = (msg & 0xfffffff0) | chan;
161         mem_barrier();
162 }
163
164 uint32_t rpi_mbox_recv(int chan)
165 {
166         uint32_t msg;
167         mem_barrier();
168         do {
169                 while(MBOX_STATUS_REG & MBOX_STAT_EMPTY);
170                 msg = MBOX_READ_REG;
171         } while((msg & 0xf) != chan);
172         mem_barrier();
173         return msg & 0xfffffff0;
174 }
175
176 int rpi_mbox_pending(int chan)
177 {
178         mem_barrier();
179         return (MBOX_STATUS_REG & MBOX_STAT_EMPTY) == 0;
180 }
181
182
183 static struct {
184         int id, req_len, resp_len;
185 } taginfo[] = {
186         {RPI_TAG_GETMODEL, 0, 4},
187         {RPI_TAG_GETREV, 0, 4},
188         {RPI_TAG_GETRAM, 0, 8},
189         {RPI_TAG_GETVRAM, 0, 8},
190         {RPI_TAG_SETCLOCK, 4, 8},
191         {RPI_TAG_ALLOCFB, 4, 8},
192         {RPI_TAG_RELEASEFB, 0, 0},
193         {RPI_TAG_BLANKSCR, 4, 4},
194         {RPI_TAG_SETFBPHYS, 8, 8},
195         {RPI_TAG_SETFBVIRT, 8, 8},
196         {RPI_TAG_SETFBDEPTH, 4, 4},
197         {RPI_TAG_GETFBPITCH, 0, 4},
198         {RPI_TAG_SETFBOFFS, 8, 8},
199         {RPI_TAG_GETFBOFFS, 0, 8},
200         {0, 0, 0}
201 };
202
203 void rpi_prop(int id, ...)
204 {
205         int i, req_len = 0, resp_len = 0;
206         va_list ap;
207
208         if(!wrprop) {
209                 wrprop = (struct rpi_prop*)(propbuf + sizeof(struct rpi_prop_header));
210         }
211
212         for(i=0; taginfo[i].id; i++) {
213                 if(taginfo[i].id == id) {
214                         req_len = taginfo[i].req_len;
215                         resp_len = taginfo[i].resp_len;
216                         break;
217                 }
218         }
219
220         wrprop->id = id;
221         wrprop->size = resp_len;
222         wrprop->res = 0;
223
224         va_start(ap, id);
225         for(i=0; i<resp_len >> 2; i++) {
226                 if(i < req_len >> 2) {
227                         wrprop->data[i] = va_arg(ap, uint32_t);
228                 } else {
229                         wrprop->data[i] = 0;
230                 }
231         }
232         va_end(ap);
233
234         wrprop = RPI_PROP_NEXT(wrprop);
235 }
236
237 int rpi_prop_send(void)
238 {
239         struct rpi_prop_header *hdr = (struct rpi_prop_header*)propbuf;
240         uint32_t addr = (uint32_t)propbuf;
241         uint32_t size;
242
243         /* terminate with null tag */
244         wrprop->id = 0;
245
246         size = (char*)wrprop - propbuf + 4;
247
248         hdr->size = (size + 15) & 0xfffffff0;
249         hdr->res = 0;
250
251         wrprop = rdprop = 0;
252
253         /* clean and invalidate cache, otherwise VC will see stale data */
254         sysctl_dcache_clean_inval(addr, hdr->size);
255
256         rpi_mbox_send(RPI_MBOX_PROP, addr);
257         while(rpi_mbox_recv(RPI_MBOX_PROP) != addr);
258
259         sysctl_dcache_clean_inval(addr, hdr->size);
260
261         if(hdr->res != 0x80000000) {
262                 printf("Property request failed: %x\n", hdr->res);
263                 return -1;
264         }
265         return 0;
266 }
267
268 struct rpi_prop *rpi_prop_next(void)
269 {
270         struct rpi_prop *res;
271         if(!rdprop) {
272                 rdprop = (struct rpi_prop*)(propbuf + sizeof(struct rpi_prop_header));
273         }
274
275         if(rdprop->id == 0) {
276                 res = rdprop = 0;
277         } else {
278                 res = rdprop;
279                 rdprop->size = rdprop->res & 0x7fffffff;
280                 rdprop = RPI_PROP_NEXT(rdprop);
281         }
282         return res;
283 }
284
285 struct rpi_prop *rpi_prop_find(int id)
286 {
287         struct rpi_prop *prop = (struct rpi_prop*)(propbuf + sizeof(struct rpi_prop_header));
288
289         while(prop->id) {
290                 prop->size = prop->res & 0x7fffffff;
291                 if(prop->id == id) {
292                         return prop;
293                 }
294                 prop = RPI_PROP_NEXT(prop);
295         }
296         return 0;
297 }