Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/mem/minerva.c
3694 views
1
/*
2
* Copyright (c) 2019-2026 CTCaer
3
*
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms and conditions of the GNU General Public License,
6
* version 2, as published by the Free Software Foundation.
7
*
8
* This program is distributed in the hope it will be useful, but WITHOUT
9
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11
* more details.
12
*
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15
*/
16
17
#include <string.h>
18
#include <stdlib.h>
19
20
#include "minerva.h"
21
22
#include <ianos/ianos.h>
23
#include <mem/emc_t210.h>
24
#include <soc/clock.h>
25
#include <soc/fuse.h>
26
#include <soc/hw_init.h>
27
#include <soc/t210.h>
28
29
#define FREQ_NO_TABLE_MAX FREQ_408
30
31
#define TABLE_FREQ_KHZ_OFFSET 0x40
32
#define TABLE_LA_REGS_T210_OFFSET 0x1284
33
#define TABLE_LA_REGS_T210B01_OFFSET 0xFA4
34
#define LA_SDMMC1_INDEX 6
35
36
static bool no_table = false;
37
static mtc_config_t *mtc_cfg = NULL;
38
void (*mtc_call)(mtc_config_t *mtc_cfg, void *);
39
40
int minerva_init(minerva_str_t *mtc_str)
41
{
42
mtc_call = NULL;
43
mtc_cfg = (mtc_config_t *)&mtc_str->mtc_cfg;
44
no_table = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01;
45
46
#ifdef BDK_MINERVA_CFG_FROM_RAM
47
// Set table to nyx storage.
48
mtc_cfg->mtc_table = (emc_table_t *)mtc_str->mtc_table;
49
50
// Check if Minerva is already initialized.
51
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
52
{
53
// Load library and do a periodic training if needed.
54
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
55
mtc_call = (void *)ianos_static_module("bootloader/sys/libsys_minerva.bso", (void *)mtc_cfg);
56
57
return !mtc_call ? 1 : 0;
58
}
59
else
60
{
61
mtc_config_t mtc_tmp;
62
63
// Initialize table.
64
mtc_tmp.mtc_table = mtc_cfg->mtc_table;
65
mtc_tmp.sdram_id = fuse_read_dramid(false);
66
mtc_tmp.init_done = !no_table ? MTC_NEW_MAGIC : MTC_IRB_MAGIC;
67
68
// Load library and get table.
69
u32 ep_addr = ianos_static_module("bootloader/sys/libsys_minerva.bso", (void *)&mtc_tmp);
70
71
// Ensure that Minerva is initialized.
72
if (mtc_tmp.init_done == MTC_INIT_MAGIC)
73
mtc_call = (void *)ep_addr;
74
else
75
mtc_cfg->init_done = 0;
76
77
// Copy Minerva context to Nyx storage.
78
if (mtc_call)
79
memcpy(mtc_cfg, (void *)&mtc_tmp, sizeof(mtc_config_t));
80
}
81
#else
82
// Fully initialize Minerva.
83
memset(mtc_cfg, 0, sizeof(mtc_config_t));
84
85
// Initialize mtc table.
86
mtc_cfg->mtc_table = mtc_str->mtc_table;
87
mtc_cfg->sdram_id = fuse_read_dramid(false);
88
mtc_cfg->init_done = !no_table ? MTC_NEW_MAGIC : MTC_IRB_MAGIC;
89
90
u32 ep_addr = ianos_static_module("bootloader/sys/libsys_minerva.bso", (void *)mtc_cfg);
91
92
// Ensure that Minerva is initialized.
93
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
94
mtc_call = (void *)ep_addr;
95
else
96
mtc_cfg->init_done = 0;
97
#endif
98
99
if (!mtc_call)
100
return 1;
101
102
if (no_table)
103
{
104
mtc_cfg->train_mode = OP_SWITCH;
105
mtc_cfg->rate_from = FREQ_204;
106
mtc_cfg->rate_to = FREQ_NO_TABLE_MAX;
107
mtc_call(mtc_cfg, NULL);
108
109
return 0;
110
}
111
112
// Train frequencies.
113
mtc_cfg->train_mode = OP_TRAIN;
114
mtc_cfg->rate_from = FREQ_204;
115
mtc_cfg->rate_to = FREQ_204;
116
mtc_call(mtc_cfg, NULL);
117
mtc_cfg->rate_to = FREQ_800;
118
mtc_call(mtc_cfg, NULL);
119
mtc_cfg->rate_to = FREQ_1600;
120
mtc_call(mtc_cfg, NULL);
121
122
// FSP WAR.
123
mtc_cfg->train_mode = OP_SWITCH;
124
mtc_cfg->rate_to = FREQ_800;
125
mtc_call(mtc_cfg, NULL);
126
127
// Switch to max.
128
mtc_cfg->rate_to = FREQ_1600;
129
mtc_call(mtc_cfg, NULL);
130
131
return 0;
132
}
133
134
void minerva_change_freq(minerva_freq_t freq)
135
{
136
if (!mtc_call)
137
return;
138
139
// Clamp max allowed frequency when no table exists.
140
if (no_table && freq > FREQ_NO_TABLE_MAX)
141
freq = FREQ_NO_TABLE_MAX;
142
143
// Check if requested frequency is different. Do not allow otherwise because it will hang.
144
if (mtc_cfg->rate_from != freq)
145
{
146
mtc_cfg->train_mode = OP_SWITCH;
147
mtc_cfg->rate_to = freq;
148
mtc_call(mtc_cfg, NULL);
149
}
150
}
151
152
void minerva_deinit()
153
{
154
if (!mtc_cfg)
155
return;
156
157
minerva_change_freq(FREQ_204);
158
mtc_cfg->init_done = 0;
159
}
160
161
void minerva_sdmmc_la_program(void *table, bool t210b01)
162
{
163
u32 freq = *(u32 *)(table + TABLE_FREQ_KHZ_OFFSET);
164
u32 *la_scale_regs = (u32 *)(table + (t210b01 ? TABLE_LA_REGS_T210B01_OFFSET : TABLE_LA_REGS_T210_OFFSET));
165
166
// Adjust SDMMC1 latency allowance.
167
switch (freq)
168
{
169
case 204000:
170
la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 50;
171
break;
172
case 408000:
173
la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 25;
174
break;
175
default:
176
la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 20;
177
break;
178
}
179
}
180
181
void minerva_prep_boot_hos()
182
{
183
if (!mtc_call)
184
return;
185
186
// Restore boot frequency for no table mode.
187
if (no_table)
188
{
189
minerva_deinit();
190
191
return;
192
}
193
194
// Check if there's RAM OC. If not exit.
195
if (mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600)
196
return;
197
198
// FSP WAR.
199
minerva_change_freq(FREQ_204);
200
// Scale down to 800 MHz boot freq.
201
minerva_change_freq(FREQ_800);
202
}
203
204
void minerva_prep_boot_l4t(u32 oc_freq, u32 opt_custom, bool prg_sdmmc_la)
205
{
206
if (!mtc_call || no_table)
207
return;
208
209
// Program SDMMC LA regs.
210
if (prg_sdmmc_la)
211
for (u32 i = 0; i < mtc_cfg->table_entries; i++)
212
minerva_sdmmc_la_program(&mtc_cfg->mtc_table[i], false);
213
214
// Add OC frequency.
215
if (oc_freq && mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600)
216
{
217
memcpy(&mtc_cfg->mtc_table[mtc_cfg->table_entries],
218
&mtc_cfg->mtc_table[mtc_cfg->table_entries - 1],
219
sizeof(emc_table_t));
220
221
mtc_cfg->mtc_table[mtc_cfg->table_entries].opt_custom = opt_custom;
222
mtc_cfg->mtc_table[mtc_cfg->table_entries].rate_khz = oc_freq;
223
mtc_cfg->table_entries++;
224
}
225
226
// Trim table.
227
int entries = 0;
228
for (u32 i = 0; i < mtc_cfg->table_entries; i++)
229
{
230
// Copy frequencies from 204/408/800 MHz and 1333+ MHz.
231
int rate = mtc_cfg->mtc_table[i].rate_khz;
232
if (rate == FREQ_204 ||
233
rate == FREQ_408 ||
234
rate == FREQ_800 ||
235
rate >= FREQ_1333)
236
{
237
memcpy(&mtc_cfg->mtc_table[entries], &mtc_cfg->mtc_table[i], sizeof(emc_table_t));
238
entries++;
239
}
240
}
241
mtc_cfg->table_entries = entries;
242
243
// Set init frequency.
244
minerva_change_freq(FREQ_204);
245
246
// Train the rest of the frequencies.
247
mtc_cfg->train_mode = OP_TRAIN;
248
for (u32 i = 0; i < mtc_cfg->table_entries; i++)
249
{
250
// Skip already trained frequencies and OC freq (Arachne handles it).
251
if (mtc_cfg->mtc_table[i].trained || mtc_cfg->rate_to == oc_freq)
252
continue;
253
254
// Train frequency.
255
mtc_cfg->rate_to = mtc_cfg->mtc_table[i].rate_khz;
256
mtc_call(mtc_cfg, NULL);
257
}
258
259
// Do FSP WAR and scale to 800 MHz as boot freq.
260
bool fsp_opwr_disabled = !(EMC(EMC_MRW3) & 0xC0);
261
if (fsp_opwr_disabled)
262
minerva_change_freq(FREQ_1333);
263
minerva_change_freq(FREQ_800);
264
265
// Do not let other mtc ops.
266
mtc_cfg->init_done = 0;
267
}
268
269
void minerva_periodic_training()
270
{
271
if (!mtc_call)
272
return;
273
274
if (mtc_cfg->rate_from >= FREQ_1066)
275
{
276
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
277
mtc_call(mtc_cfg, NULL);
278
}
279
}
280
281
emc_table_t *minerva_get_mtc_table()
282
{
283
if (!mtc_call || no_table)
284
return NULL;
285
286
return mtc_cfg->mtc_table;
287
}
288
289
int minerva_get_mtc_table_entries()
290
{
291
if (!mtc_call || no_table)
292
return 0;
293
294
return mtc_cfg->table_entries;
295
}
296
297