ec18e96ccbe1d72005a1dfdcbc9432f69cd6b168
[rpikern] / src / rpi.c
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include "rpi.h"
4 #include "rpi_ioreg.h"
5 #include "sysctl.h"
6 #include "asm.h"
7 #include "serial.h"
8 #include "debug.h"
9
10
11 static int detect(void);
12
13 int rpi_model;
14 uint32_t rpi_iobase;
15 uint32_t rpi_mem_base, rpi_mem_size, rpi_vmem_base, rpi_vmem_size;
16
17
18 /* needs to by 16-byte aligned, because the address we send over the mailbox
19  * interface, will have its 4 least significant bits masked off and taken over
20  * by the mailbox id
21  */
22 static char propbuf[256] __attribute__((aligned(16)));
23 static struct rpi_prop *wrprop, *rdprop;
24
25
26 void rpi_init(void)
27 {
28         struct rpi_prop *prop;
29
30         if((rpi_model = detect()) == -1) {
31                 for(;;) halt_cpu();
32         }
33
34         init_serial(115200);
35
36         /* The model detected by detect is not accurate, get the correct board model
37          * through the mailbox property interface if possible.
38          * Also, detect the amount of CPU and GPU memory available.
39          */
40
41         rpi_prop(RPI_TAG_GETREV);
42         rpi_prop(RPI_TAG_GETRAM);
43         rpi_prop(RPI_TAG_GETVRAM);
44         if(rpi_prop_send() != -1) {
45                 //hexdump(propbuf, sizeof propbuf);
46
47                 while((prop = rpi_prop_next())) {
48                         switch(prop->id) {
49                         case RPI_TAG_GETREV:
50                                 printf("board revision: %x\n", prop->data[0]);
51                                 /* TODO: guess rpi model based on board revision */
52                                 break;
53
54                         case RPI_TAG_GETRAM:
55                                 rpi_mem_base = prop->data[0];
56                                 rpi_mem_size = prop->data[1];
57                                 break;
58
59                         case RPI_TAG_GETVRAM:
60                                 rpi_vmem_base = prop->data[0];
61                                 rpi_vmem_size = prop->data[1];
62                                 break;
63
64                         default:
65                                 break;
66                         }
67                 }
68         }
69 }
70
71 static int detect(void)
72 {
73         int i, j;
74         uint32_t tm0, tm1;
75         static uint32_t base[] = {0x20000000, 0x3f000000, 0xfe000000};
76
77         for(i=0; i<3; i++) {
78                 rpi_iobase = base[i];
79                 tm0 = STM_LCNT_REG;
80                 for(j=0; j<256; j++) {
81                         tm1 = STM_LCNT_REG;
82                 }
83                 if(tm0 != tm1) {
84                         return i + 1;
85                 }
86         }
87         return -1;
88 }
89
90 void rpi_reboot(void)
91 {
92         mem_barrier();
93         PM_WDOG_REG = PM_PASSWD | 1;
94         PM_RSTC_REG = PM_PASSWD | (PM_RSTC_REG & PMRSTC_WRCFG_CLEAR) | PMRSTC_WRCFG_FULL_RESET;
95         for(;;) halt_cpu();
96 }
97
98 void rpi_mbox_send(int chan, uint32_t msg)
99 {
100         mem_barrier();
101         while(MBOX_STATUS_REG & MBOX_STAT_FULL);
102         MBOX_WRITE_REG = (msg & 0xfffffff0) | chan;
103         mem_barrier();
104 }
105
106 uint32_t rpi_mbox_recv(int chan)
107 {
108         uint32_t msg;
109         mem_barrier();
110         do {
111                 while(MBOX_STATUS_REG & MBOX_STAT_EMPTY);
112                 msg = MBOX_READ_REG;
113         } while((msg & 0xf) != chan);
114         mem_barrier();
115         return msg & 0xfffffff0;
116 }
117
118 int rpi_mbox_pending(int chan)
119 {
120         mem_barrier();
121         return (MBOX_STATUS_REG & MBOX_STAT_EMPTY) == 0;
122 }
123
124
125 static struct {
126         int id, req_len, resp_len;
127 } taginfo[] = {
128         {RPI_TAG_GETMODEL, 0, 4},
129         {RPI_TAG_GETREV, 0, 4},
130         {RPI_TAG_GETRAM, 0, 8},
131         {RPI_TAG_GETVRAM, 0, 8},
132         {RPI_TAG_SETCLOCK, 4, 8},
133         {RPI_TAG_ALLOCFB, 4, 8},
134         {RPI_TAG_RELEASEFB, 0, 0},
135         {RPI_TAG_BLANKSCR, 4, 4},
136         {RPI_TAG_SETFBPHYS, 8, 8},
137         {RPI_TAG_SETFBVIRT, 8, 8},
138         {RPI_TAG_SETFBDEPTH, 4, 4},
139         {RPI_TAG_GETFBPITCH, 0, 4},
140         {RPI_TAG_SETFBOFFS, 8, 8},
141         {RPI_TAG_GETFBOFFS, 0, 8},
142         {0, 0, 0}
143 };
144
145 void rpi_prop(int id, ...)
146 {
147         int i, req_len = 0, resp_len = 0;
148         va_list ap;
149
150         if(!wrprop) {
151                 wrprop = (struct rpi_prop*)(propbuf + sizeof(struct rpi_prop_header));
152         }
153
154         for(i=0; taginfo[i].id; i++) {
155                 if(taginfo[i].id == id) {
156                         req_len = taginfo[i].req_len;
157                         resp_len = taginfo[i].resp_len;
158                         break;
159                 }
160         }
161
162         wrprop->id = id;
163         wrprop->size = resp_len;
164         wrprop->res = 0;
165
166         va_start(ap, id);
167         for(i=0; i<resp_len >> 2; i++) {
168                 if(i < req_len >> 2) {
169                         wrprop->data[i] = va_arg(ap, uint32_t);
170                 } else {
171                         wrprop->data[i] = 0;
172                 }
173         }
174         va_end(ap);
175
176         wrprop = RPI_PROP_NEXT(wrprop);
177 }
178
179 int rpi_prop_send(void)
180 {
181         struct rpi_prop_header *hdr = (struct rpi_prop_header*)propbuf;
182         uint32_t addr = (uint32_t)propbuf;
183         uint32_t size;
184
185         /* terminate with null tag */
186         wrprop->id = 0;
187
188         size = (char*)wrprop - propbuf + 4;
189
190         hdr->size = (size + 15) & 0xfffffff0;
191         hdr->res = 0;
192
193         wrprop = rdprop = 0;
194
195         /* clean and invalidate cache, otherwise VC will see stale data */
196         sysctl_dcache_clean_inval(addr, hdr->size);
197
198         rpi_mbox_send(RPI_MBOX_PROP, addr);
199         while(rpi_mbox_recv(RPI_MBOX_PROP) != addr);
200
201         sysctl_dcache_clean_inval(addr, hdr->size);
202
203         if(hdr->res != 0x80000000) {
204                 printf("Property request failed: %x\n", hdr->res);
205                 return -1;
206         }
207         return 0;
208 }
209
210 struct rpi_prop *rpi_prop_next(void)
211 {
212         struct rpi_prop *res;
213         if(!rdprop) {
214                 rdprop = (struct rpi_prop*)(propbuf + sizeof(struct rpi_prop_header));
215         }
216
217         if(rdprop->id == 0) {
218                 res = rdprop = 0;
219         } else {
220                 res = rdprop;
221                 rdprop->size = rdprop->res & 0x7fffffff;
222                 rdprop = RPI_PROP_NEXT(rdprop);
223         }
224         return res;
225 }
226
227 struct rpi_prop *rpi_prop_find(int id)
228 {
229         struct rpi_prop *prop = (struct rpi_prop*)(propbuf + sizeof(struct rpi_prop_header));
230
231         while(prop->id) {
232                 prop->size = prop->res & 0x7fffffff;
233                 if(prop->id == id) {
234                         return prop;
235                 }
236                 prop = RPI_PROP_NEXT(prop);
237         }
238         return 0;
239 }