forked from jgarff/rpi_ws281x
-
Notifications
You must be signed in to change notification settings - Fork 33
/
board_info.c
143 lines (118 loc) · 2.9 KB
/
board_info.c
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
/*
* This needs cleaning up and expanding. The MODEL_* defines shoudl be in
* board_info.h, it currently identifies everything not a B2 as a B, it
* should have an accessor function for the board model and revision, etc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "board_info.h"
enum
{
MODEL_UNKNOWN,
MODEL_A,
MODEL_A_PLUS,
MODEL_B,
MODEL_B_PLUS,
MODEL_B_2,
};
static int board_info_initialised = 0;
static int board_model = MODEL_UNKNOWN;
static int board_revision;
static void
fatal(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(1);
}
static unsigned get_dt_ranges(const char *filename, unsigned offset)
{
unsigned address = ~0;
FILE *fp = fopen(filename, "rb");
if (fp)
{
unsigned char buf[4];
fseek(fp, offset, SEEK_SET);
if (fread(buf, 1, sizeof buf, fp) == sizeof buf)
address = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
fclose(fp);
}
return address;
}
uint32_t board_info_peripheral_base_addr(void)
{
unsigned address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
board_info_init();
if (address == ~0)
{
if (board_model == MODEL_B_2)
return 0x3f000000;
else
return 0x20000000;
}
else
{
return address;
}
}
uint32_t board_info_sdram_address(void)
{
unsigned address = get_dt_ranges("/proc/device-tree/axi/vc_mem/reg", 8);
board_info_init();
if (address == ~0)
{
if (board_model == MODEL_B_2)
return 0xc0000000;
else
return 0x40000000;
}
else
{
return address;
}
}
int board_info_init(void)
{
char buf[128], revstr[128], modelstr[128];
char *ptr, *end, *res;
FILE *fp;
if (board_info_initialised)
return 0;
revstr[0] = modelstr[0] = '\0';
fp = fopen("/proc/cpuinfo", "r");
if (!fp)
fatal("Unable to open /proc/cpuinfo: %m\n");
while ((res = fgets(buf, 128, fp))) {
if (!strncasecmp("model name", buf, 8))
memcpy(modelstr, buf, 128);
else if (!strncasecmp(buf, "revision", 8))
memcpy(revstr, buf, 128);
}
fclose(fp);
if (modelstr[0] == '\0')
fatal("No 'Model name' record in /proc/cpuinfo\n");
if (revstr[0] == '\0')
fatal("No 'Revision' record in /proc/cpuinfo\n");
if (strstr(modelstr, "ARMv6"))
board_model = MODEL_B;
else if (strstr(modelstr, "ARMv7"))
board_model = MODEL_B_2;
else
fatal("Cannot parse the model name string\n");
ptr = revstr + strlen(revstr) - 3;
board_revision = strtol(ptr, &end, 16);
if (end != ptr + 2)
fatal("Failed to parse Revision string\n");
if (board_revision < 1)
fatal("Invalid board Revision\n");
else if (board_revision < 4)
board_revision = 1;
else
board_revision = 2;
board_info_initialised = 1;
return 0;
}