Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/mem/minerva.c
1476 views
1
/*
2
* Copyright (c) 2019-2024 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.h>
24
#include <soc/clock.h>
25
#include <soc/fuse.h>
26
#include <soc/hw_init.h>
27
#include <soc/t210.h>
28
#include <utils/util.h>
29
30
#define TABLE_FREQ_KHZ_OFFSET 0x40
31
#define TABLE_LA_REGS_T210_OFFSET 0x1284
32
#define TABLE_LA_REGS_T210B01_OFFSET 0xFA4
33
#define LA_SDMMC1_INDEX 6
34
35
extern volatile nyx_storage_t *nyx_str;
36
37
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
38
39
u32 minerva_init()
40
{
41
u32 tbl_idx = 0;
42
43
minerva_cfg = NULL;
44
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
45
46
//!TODO: Not supported on T210B01 yet.
47
if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01)
48
return 0;
49
50
#ifdef BDK_MINERVA_CFG_FROM_RAM
51
// Set table to nyx storage.
52
mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table;
53
54
// Check if Minerva is already initialized.
55
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
56
{
57
mtc_cfg->train_mode = OP_PERIODIC_TRAIN; // Retrain if needed.
58
u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
59
minerva_cfg = (void *)ep_addr;
60
61
return !minerva_cfg ? 1 : 0;
62
}
63
else
64
{
65
mtc_config_t mtc_tmp;
66
67
mtc_tmp.mtc_table = mtc_cfg->mtc_table;
68
mtc_tmp.sdram_id = fuse_read_dramid(false);
69
mtc_tmp.init_done = MTC_NEW_MAGIC;
70
71
u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_tmp);
72
73
// Ensure that Minerva is new.
74
if (mtc_tmp.init_done == MTC_INIT_MAGIC)
75
minerva_cfg = (void *)ep_addr;
76
else
77
mtc_cfg->init_done = 0;
78
79
// Copy Minerva context to Nyx storage.
80
if (minerva_cfg)
81
memcpy(mtc_cfg, (void *)&mtc_tmp, sizeof(mtc_config_t));
82
}
83
#else
84
memset(mtc_cfg, 0, sizeof(mtc_config_t));
85
86
// Set table to nyx storage.
87
mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table;
88
89
mtc_cfg->sdram_id = fuse_read_dramid(false);
90
mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table.
91
92
u32 ep_addr = ianos_loader("bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
93
94
// Ensure that Minerva is new.
95
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
96
minerva_cfg = (void *)ep_addr;
97
else
98
mtc_cfg->init_done = 0;
99
#endif
100
101
if (!minerva_cfg)
102
return 1;
103
104
// Get current frequency
105
u32 current_emc_clk_src = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC);
106
for (tbl_idx = 0; tbl_idx < mtc_cfg->table_entries; tbl_idx++)
107
{
108
if (current_emc_clk_src == mtc_cfg->mtc_table[tbl_idx].clk_src_emc)
109
break;
110
}
111
112
mtc_cfg->rate_from = mtc_cfg->mtc_table[tbl_idx].rate_khz;
113
mtc_cfg->rate_to = FREQ_204;
114
mtc_cfg->train_mode = OP_TRAIN;
115
minerva_cfg(mtc_cfg, NULL);
116
mtc_cfg->rate_to = FREQ_800;
117
minerva_cfg(mtc_cfg, NULL);
118
mtc_cfg->rate_to = FREQ_1600;
119
minerva_cfg(mtc_cfg, NULL);
120
121
// FSP WAR.
122
mtc_cfg->train_mode = OP_SWITCH;
123
mtc_cfg->rate_to = FREQ_800;
124
minerva_cfg(mtc_cfg, NULL);
125
126
// Switch to max.
127
mtc_cfg->rate_to = FREQ_1600;
128
minerva_cfg(mtc_cfg, NULL);
129
130
return 0;
131
}
132
133
void minerva_change_freq(minerva_freq_t freq)
134
{
135
if (!minerva_cfg)
136
return;
137
138
// Check if requested frequency is different. Do not allow otherwise because it will hang.
139
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
140
if (mtc_cfg->rate_from != freq)
141
{
142
mtc_cfg->rate_to = freq;
143
mtc_cfg->train_mode = OP_SWITCH;
144
minerva_cfg(mtc_cfg, NULL);
145
}
146
}
147
148
void minerva_sdmmc_la_program(void *table, bool t210b01)
149
{
150
151
u32 freq = *(u32 *)(table + TABLE_FREQ_KHZ_OFFSET);
152
u32 *la_scale_regs = (u32 *)(table + (t210b01 ? TABLE_LA_REGS_T210B01_OFFSET : TABLE_LA_REGS_T210_OFFSET));
153
154
// Adjust SDMMC1 latency allowance.
155
switch (freq)
156
{
157
case 204000:
158
la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 50;
159
break;
160
case 408000:
161
la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 25;
162
break;
163
default:
164
la_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 20;
165
break;
166
}
167
}
168
169
void minerva_prep_boot_freq()
170
{
171
if (!minerva_cfg)
172
return;
173
174
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
175
176
// Check if there's RAM OC. If not exit.
177
if (mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600)
178
return;
179
180
// FSP WAR.
181
minerva_change_freq(FREQ_204);
182
// Scale down to 800 MHz boot freq.
183
minerva_change_freq(FREQ_800);
184
}
185
186
void minerva_prep_boot_l4t(u32 oc_freq, u32 opt_custom)
187
{
188
if (!minerva_cfg)
189
return;
190
191
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
192
193
// Program SDMMC LA regs.
194
for (u32 i = 0; i < mtc_cfg->table_entries; i++)
195
minerva_sdmmc_la_program(&mtc_cfg->mtc_table[i], false);
196
197
// Add OC frequency.
198
if (oc_freq && mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600)
199
{
200
memcpy(&mtc_cfg->mtc_table[mtc_cfg->table_entries],
201
&mtc_cfg->mtc_table[mtc_cfg->table_entries - 1],
202
sizeof(emc_table_t));
203
204
mtc_cfg->mtc_table[mtc_cfg->table_entries].opt_custom = opt_custom;
205
mtc_cfg->mtc_table[mtc_cfg->table_entries].rate_khz = oc_freq;
206
mtc_cfg->table_entries++;
207
}
208
209
// Trim table.
210
int entries = 0;
211
for (u32 i = 0; i < mtc_cfg->table_entries; i++)
212
{
213
// Copy frequencies from 204/408/800 MHz and 1333+ MHz.
214
int rate = mtc_cfg->mtc_table[i].rate_khz;
215
if (rate == FREQ_204 ||
216
rate == FREQ_408 ||
217
rate == FREQ_800 ||
218
rate >= FREQ_1333)
219
{
220
memcpy(&mtc_cfg->mtc_table[entries], &mtc_cfg->mtc_table[i], sizeof(emc_table_t));
221
entries++;
222
}
223
}
224
mtc_cfg->table_entries = entries;
225
226
// Set init frequency.
227
minerva_change_freq(FREQ_204);
228
229
// Train the rest of the frequencies.
230
mtc_cfg->train_mode = OP_TRAIN;
231
for (u32 i = 0; i < mtc_cfg->table_entries; i++)
232
{
233
// Skip already trained frequencies and OC freq (Arachne handles it).
234
if (mtc_cfg->mtc_table[i].trained || mtc_cfg->rate_to == oc_freq)
235
continue;
236
237
// Train frequency.
238
mtc_cfg->rate_to = mtc_cfg->mtc_table[i].rate_khz;
239
minerva_cfg(mtc_cfg, NULL);
240
}
241
242
// Do FSP WAR and scale to 800 MHz as boot freq.
243
bool fsp_opwr_disabled = !(EMC(EMC_MRW3) & 0xC0);
244
if (fsp_opwr_disabled)
245
minerva_change_freq(FREQ_1333);
246
minerva_change_freq(FREQ_800);
247
248
// Do not let other mtc ops.
249
mtc_cfg->init_done = 0;
250
}
251
252
void minerva_periodic_training()
253
{
254
if (!minerva_cfg)
255
return;
256
257
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
258
if (mtc_cfg->rate_from == FREQ_1600)
259
{
260
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
261
minerva_cfg(mtc_cfg, NULL);
262
}
263
}
264
265
emc_table_t *minerva_get_mtc_table()
266
{
267
if (!minerva_cfg)
268
return NULL;
269
270
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
271
return mtc_cfg->mtc_table;
272
}
273
274
int minerva_get_mtc_table_entries()
275
{
276
if (!minerva_cfg)
277
return 0;
278
279
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
280
return mtc_cfg->table_entries;
281
}
282
283