blob: 5334845600b0727aa5472b8a6f89be6cc6c6d9fe (
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
|
#include "common/types.h"
#include "drivers/uart.h"
#include "kernel/config.h"
#include "lib/string.h"
inline uint32_t bswap(uint32_t x)
{
return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) |
((x & 0xFF0000) >> 8) | ((x >> 24) & 0xFF);
}
struct fdt_header
{
uint32 magic;
uint32 totalsize;
uint32 off_dt_struct;
uint32 off_dt_strings;
uint32 off_mem_rsvmap;
uint32 version;
uint32 last_comp_version;
uint32 boot_cpuid_phys;
uint32 size_dt_strings;
uint32 size_dt_struct;
};
#define FDT_MAGIC 0xd00dfeed
#define FDT_BEGIN_NODE 1
#define FDT_END_NODE 2
#define FDT_PROP 3
#define FDT_NOP 4
#define FDT_END 9
void fdt_init(uint64 dtb)
{
if (dtb == 0) return;
struct fdt_header* header = (struct fdt_header*)dtb;
if (bswap(header->magic) != FDT_MAGIC)
return;
uint8* struct_ptr = (uint8*)(dtb + bswap(header->off_dt_struct));
char* strings_ptr = (char *)(dtb + bswap(header->off_dt_strings));
uint64 current_reg_addr = 0;
while (1)
{
uint32 token = bswap(*(uint32*)struct_ptr);
struct_ptr += 4;
if(token == FDT_END)break;
if(token == FDT_NOP)continue;
if(token == FDT_BEGIN_NODE)
{
while (*struct_ptr != 0)struct_ptr++;
struct_ptr++;
struct_ptr = (uint8*)(((uint64)struct_ptr + 3) & ~3);
}
else if(token == FDT_END_NODE)
{
}
else if (token == FDT_PROP)
{
uint32 len = bswap(*(uint32*)struct_ptr);
struct_ptr += 4;
uint32 nameoff = bswap(*(uint32*)struct_ptr);
struct_ptr += 4;
char* name = strings_ptr + nameoff;
uint8* data = struct_ptr;
struct_ptr += len;
struct_ptr = (uint8*)(((uint64)struct_ptr + 3) & ~3);
if(strcmp(name, "reg") == 0 && len >= 8)
{
uint32 hi = bswap(*(uint32*)data);
uint32 lo = bswap(*(uint32*)(data + 4));
current_reg_addr = ((uint64)hi << 32) | lo;
}
if(strcmp(name, "compatible") == 0)
{
if (g_uart_base == 0)
{
for(uint32 i = 0; i < len; i++)
{
if (data[i] == 'n' && data[i + 1] == 's' && data[i + 2] == '1')
{
g_uart_base = current_reg_addr;
break;
}
}
}
}
}
}
}
|