blob: 5f1150c0c7700124b08cf6eb78217e5e5cc7d39b [file] [log] [blame]
Stephan Gerhold3f1d3e42020-01-04 18:45:19 +01001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2019 Stephan Gerhold <stephan@gerhold.net>
4 */
5#include <common.h>
Stephan Gerholdfa307622021-07-07 12:58:55 +02006#include <env.h>
Simon Glass97589732020-05-10 11:40:02 -06007#include <init.h>
Stephan Gerholdaee9df32021-07-07 12:58:54 +02008#include <log.h>
Stephan Gerholdfa307622021-07-07 12:58:55 +02009#include <stdlib.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060010#include <asm/global_data.h>
Stephan Gerholdaee9df32021-07-07 12:58:54 +020011#include <asm/setup.h>
12#include <asm/system.h>
Stephan Gerhold3f1d3e42020-01-04 18:45:19 +010013
14DECLARE_GLOBAL_DATA_PTR;
15
Stephan Gerholdaee9df32021-07-07 12:58:54 +020016/* Parse atags provided by Samsung bootloader to get available memory */
17static ulong fw_mach __section(".data");
18static ulong fw_atags __section(".data");
19
Stephan Gerholdfa307622021-07-07 12:58:55 +020020static const struct tag *fw_atags_copy;
21static uint fw_atags_size;
22
Stephan Gerholdaee9df32021-07-07 12:58:54 +020023void save_boot_params(ulong r0, ulong r1, ulong r2, ulong r3)
24{
25 fw_mach = r1;
26 fw_atags = r2;
27 save_boot_params_ret();
28}
29
30static const struct tag *fw_atags_get(void)
31{
32 const struct tag *tags = (const struct tag *)fw_atags;
33
34 if (tags->hdr.tag != ATAG_CORE) {
35 log_err("Invalid atags: tag 0x%x at %p\n", tags->hdr.tag, tags);
36 return NULL;
37 }
38
39 return tags;
40}
41
Stephan Gerhold3f1d3e42020-01-04 18:45:19 +010042int dram_init(void)
43{
Stephan Gerholdaee9df32021-07-07 12:58:54 +020044 const struct tag *t, *tags = fw_atags_get();
45
46 if (!tags)
47 return -EINVAL;
48
49 for_each_tag(t, tags) {
50 if (t->hdr.tag != ATAG_MEM)
51 continue;
52
53 debug("Memory: %#x-%#x (size %#x)\n", t->u.mem.start,
54 t->u.mem.start + t->u.mem.size, t->u.mem.size);
55 gd->ram_size += t->u.mem.size;
56 }
57 return 0;
58}
59
60int dram_init_banksize(void)
61{
62 const struct tag *t, *tags = fw_atags_get();
63 unsigned int bank = 0;
64
65 if (!tags)
66 return -EINVAL;
67
68 for_each_tag(t, tags) {
69 if (t->hdr.tag != ATAG_MEM)
70 continue;
71
72 gd->bd->bi_dram[bank].start = t->u.mem.start;
73 gd->bd->bi_dram[bank].size = t->u.mem.size;
74 if (++bank == CONFIG_NR_DRAM_BANKS)
75 break;
76 }
Stephan Gerhold3f1d3e42020-01-04 18:45:19 +010077 return 0;
78}
79
80int board_init(void)
81{
Stephan Gerholdaee9df32021-07-07 12:58:54 +020082 gd->bd->bi_arch_number = fw_mach;
83 gd->bd->bi_boot_params = fw_atags;
Stephan Gerhold3f1d3e42020-01-04 18:45:19 +010084 return 0;
85}
Stephan Gerholdfa307622021-07-07 12:58:55 +020086
87static void parse_serial(const struct tag_serialnr *serialnr)
88{
89 char serial[17];
90
91 if (env_get("serial#"))
92 return;
93
94 sprintf(serial, "%08x%08x", serialnr->high, serialnr->low);
95 env_set("serial#", serial);
96}
97
98/*
99 * The downstream/vendor kernel (provided by Samsung) uses ATAGS for booting.
100 * It also requires an extremely long cmdline provided by the primary bootloader
101 * that is not suitable for booting mainline.
102 *
103 * Since downstream is the only user of ATAGS, we emulate the behavior of the
104 * Samsung bootloader by generating only the initrd atag in U-Boot, and copying
105 * all other ATAGS as-is from the primary bootloader.
106 */
107static inline bool skip_atag(u32 tag)
108{
109 return (tag == ATAG_NONE || tag == ATAG_CORE ||
110 tag == ATAG_INITRD || tag == ATAG_INITRD2);
111}
112
113static void copy_atags(const struct tag *tags)
114{
115 const struct tag *t;
116 struct tag *copy;
117
118 if (!tags)
119 return;
120
121 /* Calculate necessary size for tags we want to copy */
122 for_each_tag(t, tags) {
123 if (skip_atag(t->hdr.tag))
124 continue;
125
126 if (t->hdr.tag == ATAG_SERIAL)
127 parse_serial(&t->u.serialnr);
128
129 fw_atags_size += t->hdr.size * sizeof(u32);
130 }
131
132 if (!fw_atags_size)
133 return; /* No tags to copy */
134
135 copy = malloc(fw_atags_size);
136 if (!copy)
137 return;
138 fw_atags_copy = copy;
139
140 /* Copy tags */
141 for_each_tag(t, tags) {
142 if (skip_atag(t->hdr.tag))
143 continue;
144
145 memcpy(copy, t, t->hdr.size * sizeof(u32));
146 copy = tag_next(copy);
147 }
148}
149
150int misc_init_r(void)
151{
152 copy_atags(fw_atags_get());
153 return 0;
154}
155
156void setup_board_tags(struct tag **in_params)
157{
158 if (!fw_atags_copy)
159 return;
160
161 /*
162 * fw_atags_copy contains only full "struct tag" (plus data)
163 * so copying it bytewise here should be fine.
164 */
165 memcpy(*in_params, fw_atags_copy, fw_atags_size);
166 *(u8 **)in_params += fw_atags_size;
167}