Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/nyx/nyx_gui/frontend/gui_info.c
3711 views
1
/*
2
* Copyright (c) 2018 naehrwert
3
* Copyright (c) 2018-2026 CTCaer
4
* Copyright (c) 2018 balika011
5
*
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms and conditions of the GNU General Public License,
8
* version 2, as published by the Free Software Foundation.
9
*
10
* This program is distributed in the hope it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
* more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include <bdk.h>
20
21
#include "gui.h"
22
#include "../config.h"
23
#include "../hos/hos.h"
24
#include "../hos/pkg1.h"
25
#include <libs/fatfs/ff.h>
26
27
#include <stdlib.h>
28
29
#define SECTORS_TO_MIB_COEFF 11
30
31
static const char base36[37] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
32
33
extern volatile nyx_storage_t *nyx_str;
34
35
extern lv_res_t launch_payload(lv_obj_t *list);
36
extern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
37
38
static lv_res_t _create_window_dump_done(int error, char *dump_filenames)
39
{
40
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
41
lv_obj_set_style(dark_bg, &mbox_darken);
42
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
43
44
static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
45
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
46
lv_mbox_set_recolor_text(mbox, true);
47
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);
48
49
char *txt_buf = (char *)malloc(SZ_4K);
50
51
if (error)
52
s_printf(txt_buf, "#FFDD00 Failed to dump to# %s#FFDD00 !#\nError: %d", dump_filenames, error);
53
else
54
{
55
char *sn = emmcsn_path_impl(NULL, NULL, NULL, NULL);
56
s_printf(txt_buf, "Dumping to SD card finished!\nFiles: #C7EA46 backup/%s/dumps/#\n%s", sn, dump_filenames);
57
}
58
lv_mbox_set_text(mbox, txt_buf);
59
free(txt_buf);
60
61
lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action); // Important. After set_text.
62
63
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
64
lv_obj_set_top(mbox, true);
65
66
return LV_RES_OK;
67
}
68
69
static lv_res_t _cal0_dump_window_action(lv_obj_t *btns, const char * txt)
70
{
71
int btn_idx = lv_btnm_get_pressed(btns);
72
73
nyx_mbox_action(btns, txt);
74
75
if (btn_idx == 1)
76
{
77
int error = sd_mount();
78
79
if (!error)
80
{
81
char path[64];
82
emmcsn_path_impl(path, "/dumps", "cal0.bin", NULL);
83
error = sd_save_to_file((u8 *)cal0_buf, SZ_32K, path);
84
85
sd_unmount();
86
}
87
88
_create_window_dump_done(error, "cal0.bin");
89
}
90
91
return LV_RES_INV;
92
}
93
94
95
static lv_res_t _battery_dump_window_action(lv_obj_t * btn)
96
{
97
int error = sd_mount();
98
99
if (!error)
100
{
101
char path[64];
102
void *buf = malloc(0x100 * 2);
103
104
max17050_dump_regs(buf);
105
106
emmcsn_path_impl(path, "/dumps", "fuel_gauge.bin", NULL);
107
error = sd_save_to_file((u8 *)buf, 0x200, path);
108
109
sd_unmount();
110
}
111
112
_create_window_dump_done(error, "fuel_gauge.bin");
113
114
return LV_RES_OK;
115
}
116
117
static lv_res_t _bootrom_dump_window_action(lv_obj_t * btn)
118
{
119
static const u32 BOOTROM_SIZE = 0x18000;
120
121
int error = sd_mount();
122
if (!error)
123
{
124
char path[64];
125
u32 iram_evp_thunks[0x200];
126
u32 iram_evp_thunks_len = sizeof(iram_evp_thunks);
127
error = fuse_read_evp_thunk(iram_evp_thunks, &iram_evp_thunks_len);
128
if (!error)
129
{
130
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
131
error = sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path);
132
}
133
else
134
error = 255;
135
136
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
137
int res = sd_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path);
138
if (!error)
139
error = res;
140
141
u32 ipatch_cam[IPATCH_CAM_ENTRIES + 1];
142
memcpy(ipatch_cam, (void *)IPATCH_BASE, sizeof(ipatch_cam));
143
memset((void*)IPATCH_BASE, 0, sizeof(ipatch_cam)); // Zeroing valid entries is enough but zero everything.
144
145
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
146
res = sd_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path);
147
if (!error)
148
error = res;
149
150
memcpy((void*)IPATCH_BASE, ipatch_cam, sizeof(ipatch_cam));
151
152
sd_unmount();
153
}
154
_create_window_dump_done(error, "evp_thunks.bin, bootrom_patched.bin, bootrom_unpatched.bin");
155
156
return LV_RES_OK;
157
}
158
159
static u8 _ccplex_set_fuse_rd_tz[] = {
160
0xC1, 0x00, 0x00, 0x18, // 0x00: LDR W1, =APB_MISC_PP_FUSE_READ_TZ
161
0xE0, 0x03, 0x80, 0xD2, // 0x04: MOV X0, #0x1F
162
0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1]
163
0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS
164
0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH
165
0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop
166
0xA4, 0x00, 0x00, 0x70, // 0x18: APB_MISC_PP_FUSE_READ_TZ/////////////////////check default value for sure
167
};
168
169
static void _unlock_reserved_odm_fuses(bool lock)
170
{
171
_ccplex_set_fuse_rd_tz[4] = lock ? 0xE0 : 0x00;
172
_ccplex_set_fuse_rd_tz[5] = lock ? 0x03 : 0x00;
173
174
// Launch payload on CCPLEX EL3 in order to unlock reserved ODM8-29 fuses.
175
ccplex_boot_cpu0((u32)_ccplex_set_fuse_rd_tz, false);
176
msleep(100);
177
ccplex_powergate_cpu0();
178
}
179
180
static lv_res_t _fuse_dump_window_action(lv_obj_t * btn)
181
{
182
int error = sd_mount();
183
if (!error)
184
{
185
char path[128];
186
if (!h_cfg.t210b01)
187
{
188
emmcsn_path_impl(path, "/dumps", "fuse_cached_t210.bin", NULL);
189
error = sd_save_to_file((u8 *)0x7000F900, 0x300, path);
190
emmcsn_path_impl(path, "/dumps", "fuse_array_raw_t210.bin", NULL);
191
}
192
else
193
{
194
// Unlock all reserved ODM fuses.
195
_unlock_reserved_odm_fuses(false);
196
197
emmcsn_path_impl(path, "/dumps", "fuse_cached_t210b01_x898.bin", NULL);
198
error = sd_save_to_file((u8 *)0x7000F898, 0x68, path);
199
emmcsn_path_impl(path, "/dumps", "fuse_cached_t210b01_x900.bin", NULL);
200
if (!error)
201
error = sd_save_to_file((u8 *)0x7000F900, 0x300, path);
202
emmcsn_path_impl(path, "/dumps", "fuse_array_raw_t210b01.bin", NULL);
203
}
204
205
if (!error)
206
{
207
u32 words[FUSE_ARRAY_WORDS_NUM_B01];
208
u32 array_size = fuse_read_array(words);
209
error = sd_save_to_file((u8 *)words, array_size * sizeof(u32), path);
210
}
211
212
// Relock.
213
if (h_cfg.t210b01)
214
_unlock_reserved_odm_fuses(true);
215
216
sd_unmount();
217
}
218
219
if (!h_cfg.t210b01)
220
_create_window_dump_done(error, "fuse_cached_t210.bin, fuse_array_raw_t210.bin");
221
else
222
_create_window_dump_done(error, "fuse_cached_t210b01_x*.bin, fuse_array_raw_t210b01.bin");
223
224
return LV_RES_OK;
225
}
226
227
static lv_res_t _kfuse_dump_window_action(lv_obj_t * btn)
228
{
229
u32 buf[KFUSE_NUM_WORDS];
230
int error = kfuse_read(buf);
231
232
if (!error)
233
error = sd_mount();
234
235
if (!error)
236
{
237
char path[64];
238
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
239
error = sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path);
240
241
sd_unmount();
242
}
243
244
_create_window_dump_done(error, "kfuses.bin");
245
246
return LV_RES_OK;
247
}
248
249
static lv_res_t _create_mbox_cal0(lv_obj_t *btn)
250
{
251
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
252
lv_obj_set_style(dark_bg, &mbox_darken);
253
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
254
255
static const char * mbox_btn_map[] = { "\251", "\222Dump", "\222Close", "\251", "" };
256
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
257
lv_mbox_set_recolor_text(mbox, true);
258
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);
259
260
lv_mbox_set_text(mbox, "#C7EA46 CAL0 Info#");
261
262
char *txt_buf = (char *)malloc(SZ_16K);
263
txt_buf[0] = 0;
264
265
lv_obj_t * lb_desc = lv_label_create(mbox, NULL);
266
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
267
lv_label_set_recolor(lb_desc, true);
268
lv_label_set_style(lb_desc, &monospace_text);
269
lv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4);
270
271
sd_mount();
272
273
// Dump CAL0.
274
int cal0_res = hos_dump_cal0();
275
276
// Check result. Don't error if hash doesn't match.
277
if (cal0_res == 1)
278
{
279
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
280
281
goto out;
282
}
283
else if (cal0_res == 2)
284
{
285
lv_label_set_text(lb_desc, "#FFDD00 CAL0 is corrupt or wrong keys!#\n");
286
goto out;
287
}
288
289
nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf;
290
291
u32 hash[8];
292
se_sha_hash_256_oneshot(hash, (u8 *)&cal0->cfg_id1, cal0->body_size);
293
294
s_printf(txt_buf,
295
"#FF8000 CAL0 Version:# %d\n"
296
"#FF8000 Update Count:# %d\n"
297
"#FF8000 Serial Number:# %s\n"
298
"#FF8000 WLAN MAC:# %02X:%02X:%02X:%02X:%02X:%02X\n"
299
"#FF8000 Bluetooth MAC:# %02X:%02X:%02X:%02X:%02X:%02X\n"
300
"#FF8000 Battery LOT:# %s (%d)\n"
301
"#FF8000 LCD Vendor:# ",
302
cal0->version, cal0->update_cnt, cal0->serial_number,
303
cal0->wlan_mac[0], cal0->wlan_mac[1], cal0->wlan_mac[2], cal0->wlan_mac[3], cal0->wlan_mac[4], cal0->wlan_mac[5],
304
cal0->bd_mac[0], cal0->bd_mac[1], cal0->bd_mac[2], cal0->bd_mac[3], cal0->bd_mac[4], cal0->bd_mac[5],
305
cal0->battery_lot, cal0->battery_ver);
306
307
// Prepare display info.
308
u32 display_id = (cal0->lcd_vendor & 0xFF) << 8 | (cal0->lcd_vendor & 0xFF0000) >> 16;
309
switch (display_id)
310
{
311
case PANEL_JDI_LAM062M109A:
312
strcat(txt_buf, "JDI LAM062M109A");
313
break;
314
case PANEL_JDI_LPM062M326A:
315
strcat(txt_buf, "JDI LPM062M326A");
316
break;
317
case PANEL_INL_P062CCA_AZ1:
318
strcat(txt_buf, "InnoLux P062CCA-AZX");
319
break;
320
case PANEL_AUO_A062TAN01:
321
strcat(txt_buf, "AUO A062TAN0X");
322
break;
323
case PANEL_INL_2J055IA_27A:
324
strcat(txt_buf, "InnoLux 2J055IA-27A");
325
break;
326
case PANEL_AUO_A055TAN01:
327
strcat(txt_buf, "AUO A055TAN0X");
328
break;
329
case PANEL_SHP_LQ055T1SW10:
330
strcat(txt_buf, "Sharp LQ055T1SW10");
331
break;
332
case PANEL_SAM_AMS699VC01:
333
strcat(txt_buf, "Samsung AMS699VC01");
334
break;
335
default:
336
switch (cal0->lcd_vendor & 0xFF)
337
{
338
case 0:
339
case PANEL_JDI_XXX062M:
340
strcat(txt_buf, "JDI ");
341
break;
342
case (PANEL_INL_P062CCA_AZ1 & 0xFF):
343
strcat(txt_buf, "InnoLux ");
344
break;
345
case (PANEL_AUO_A062TAN01 & 0xFF):
346
strcat(txt_buf, "AUO ");
347
break;
348
case (PANEL_SAM_AMS699VC01 & 0xFF):
349
strcat(txt_buf, "Samsung ");
350
break;
351
}
352
strcat(txt_buf, "Unknown");
353
break;
354
}
355
356
s_printf(txt_buf + strlen(txt_buf),
357
" (%06X)\n#FF8000 Touch Vendor:# %d\n"
358
"#FF8000 IMU Type/Mount:# %d / %d\n"
359
"#FF8000 Stick L/R Type:# %02X / %02X\n",
360
cal0->lcd_vendor, cal0->touch_ic_vendor_id,
361
cal0->console_6axis_sensor_type, cal0->console_6axis_sensor_mount_type,
362
cal0->analog_stick_type_l, cal0->analog_stick_type_r);
363
364
bool valid_cal0 = !memcmp(hash, cal0->body_sha256, 0x20);
365
s_printf(txt_buf + strlen(txt_buf), "#FF8000 SHA256 Hash Match:# %s", valid_cal0 ? "Pass" : "Failed");
366
367
lv_label_set_text(lb_desc, txt_buf);
368
369
out:
370
free(txt_buf);
371
sd_unmount();
372
373
lv_mbox_add_btns(mbox, mbox_btn_map, _cal0_dump_window_action);
374
375
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
376
lv_obj_set_top(mbox, true);
377
378
return LV_RES_OK;
379
}
380
381
u32 wafer16nm[] =
382
{
383
0x0003F800, 0x001FFF00, 0x007FFFC0, 0x00FFFFE0,
384
0x01FFFFF0, 0x03FFFFF8, 0x07FFFFFC, 0x07FFFFFC,
385
0x0FFFFFFE, 0x0FFFFFFE, 0x0FFFFFFE, 0x1FFFFFFF,
386
0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,
387
0x1FFFFFFF, 0x1FFFFFFF, 0x0FFFFFFE, 0x0FFFFFFE,
388
0x0FFFFFFE, 0x07FFFFFC, 0x07FFFFFC, 0x03FFFFF8,
389
0x01FFFFF0, 0x00FFFFE0, 0x007FFFC0, 0x001FFF00,
390
0x0000E000
391
};
392
393
u32 wafer20nm[] =
394
{
395
0x0001FE00, 0x0007FF80, 0x001FFFE0, 0x003FFFF0,
396
0x007FFFF8, 0x00FFFFFC, 0x00FFFFFC, 0x01FFFFFE,
397
0x01FFFFFE, 0x03FFFFFF, 0x03FFFFFF, 0x03FFFFFF,
398
0x03FFFFFF, 0x03FFFFFF, 0x03FFFFFF, 0x03FFFFFF,
399
0x03FFFFFF, 0x01FFFFFE, 0x01FFFFFE, 0x00FFFFFC,
400
0x00FFFFFC, 0x007FFFF8, 0x003FFFF0, 0x001FFFE0,
401
0x0007FF80,
402
0x00000000,
403
};
404
405
typedef struct _hw_info_t
406
{
407
lv_obj_t *ver;
408
lv_obj_t *wafer_img;
409
lv_obj_t *wafer_txt;
410
} hw_info_t;
411
412
hw_info_t *hw_info = NULL;
413
414
//! TODO: Limits assumed based on known samples.
415
#define WAFER_20NM_X_MIN -9
416
#define WAFER_20NM_X_MAX 15
417
#define WAFER_20NM_Y_MIN 1
418
#define WAFER_20NM_Y_MAX 24
419
420
// Limits validated based on known samples.
421
#define WAFER_16NM_X_MIN -11
422
#define WAFER_16NM_X_MAX 17
423
#define WAFER_16NM_Y_MIN 0
424
#define WAFER_16NM_Y_MAX 28
425
426
void _hw_info_wafer(int die_x, int die_y)
427
{
428
static lv_img_dsc_t wafer_desc = { 0 };
429
int diameter;
430
431
if (h_cfg.t210b01)
432
{
433
if (die_x < WAFER_16NM_X_MIN || die_x > WAFER_16NM_X_MAX ||
434
die_y < WAFER_16NM_Y_MIN || die_y > WAFER_16NM_Y_MAX)
435
die_x = WAFER_16NM_X_MIN - 1;
436
437
die_x += -WAFER_16NM_X_MIN;
438
diameter = 29;
439
}
440
else
441
{
442
if (die_x < WAFER_20NM_X_MIN || die_x > WAFER_20NM_X_MAX ||
443
die_y < 0 || die_y > WAFER_20NM_Y_MAX)
444
die_x = WAFER_20NM_X_MIN - 1;
445
446
die_x += -WAFER_20NM_X_MIN;
447
diameter = 26;
448
}
449
450
const u32 die_size = 2;
451
const u32 die_side = die_size + 1;
452
const u32 die_line = die_side * diameter + 1;
453
const int align_off = (die_size - 2) * diameter;
454
const u32 die_color = (die_x == -1) ? 0xFFFF0000 : 0x30FFFFFF; // Red for OOB.
455
const u32 str_color = 0x10FFFFFF;
456
const u32 hit_color = 0xFFFF8000;
457
458
u32 *wafer_map = zalloc(die_line * die_line * sizeof(u32));
459
460
for (int y = 0; y < diameter; y++)
461
{
462
u32 wafer_row_next = -1;
463
u32 wafer_row = h_cfg.t210b01 ? wafer16nm[y] : wafer20nm[y];
464
465
if ((y + 1) < diameter)
466
wafer_row_next = h_cfg.t210b01 ? wafer16nm[y + 1] : wafer20nm[y + 1];
467
468
// Paint the first row of dies.
469
int pos_y = y * die_line * die_side + die_line;
470
for (int x = 0; x < diameter; x++)
471
{
472
bool in_wafer = wafer_row & (1u << x);
473
bool die_found = x == die_x && die_y == y;
474
u32 die_column = x * die_side;
475
476
// Paint street rows;
477
if (in_wafer)
478
for (u32 i = 0; i < die_size + 2; i++)
479
{
480
wafer_map[pos_y - die_line + die_column + i] = str_color;
481
if (wafer_row > wafer_row_next)
482
wafer_map[pos_y - die_line + die_column + i + die_line * die_side] = str_color;
483
}
484
485
// Paint street column;
486
if (in_wafer)
487
wafer_map[pos_y + die_column] = str_color;
488
489
u32 color;
490
if (in_wafer && !die_found)
491
color = die_color;
492
else
493
color = !die_found ? 0 : hit_color;
494
495
// Paint die row0;
496
for (u32 i = 0; i < die_size; i++)
497
wafer_map[pos_y + die_column + 1 + i] = color;
498
499
// Paint street column;
500
if (in_wafer)
501
wafer_map[pos_y + die_column + 1 + die_size] = str_color;
502
}
503
504
// Paint the rest of die rows.
505
for (u32 i = 1; i < die_size; i++)
506
memcpy(&wafer_map[pos_y + die_line * i], &wafer_map[pos_y], die_line * sizeof(u32));
507
}
508
509
wafer_desc.header.always_zero = 0;
510
wafer_desc.header.w = die_line;
511
wafer_desc.header.h = die_line;
512
wafer_desc.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
513
wafer_desc.data_size = die_line * die_line * sizeof(u32);
514
wafer_desc.data = (u8 *)wafer_map;
515
516
lv_obj_t *wafer_img = lv_img_create(lv_scr_act(), NULL);
517
lv_img_set_src(wafer_img, &wafer_desc);
518
if (h_cfg.t210b01)
519
lv_obj_align(wafer_img, NULL, LV_ALIGN_IN_TOP_LEFT, LV_DPI * 58 / 11 - align_off, LV_DPI * 44 / 9 - align_off / 2);
520
else
521
lv_obj_align(wafer_img, NULL, LV_ALIGN_IN_TOP_LEFT, LV_DPI * 59 / 11 - align_off, LV_DPI * 74 / 15 - align_off / 2);
522
hw_info->wafer_img = wafer_img;
523
524
lv_obj_t *wafer_txt = lv_label_create(lv_scr_act(), NULL);
525
lv_label_set_style(wafer_txt, &monospace_text);
526
lv_label_set_static_text(wafer_txt, (die_x == -1) ? "Error" : "Wafer");
527
lv_obj_align(wafer_txt, wafer_img, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
528
hw_info->wafer_txt = wafer_txt;
529
}
530
531
static lv_res_t _action_win_hw_info_status_close(lv_obj_t *btn)
532
{
533
if (hw_info)
534
{
535
lv_img_dsc_t *wafer_dsc = (lv_img_dsc_t *)lv_img_get_src(hw_info->wafer_img);
536
lv_obj_del(hw_info->ver);
537
lv_obj_del(hw_info->wafer_img);
538
lv_obj_del(hw_info->wafer_txt);
539
free((u32 *)wafer_dsc->data);
540
free(hw_info);
541
hw_info = NULL;
542
}
543
544
return nyx_win_close_action(btn);
545
}
546
547
static lv_res_t _create_window_hw_info_status(lv_obj_t *btn)
548
{
549
u32 uptime_s = get_tmr_s();
550
551
lv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP" HW & Fuses Info", _action_win_hw_info_status_close);
552
lv_win_add_btn(win, NULL, SYMBOL_DOWNLOAD" Dump fuses", _fuse_dump_window_action);
553
lv_win_add_btn(win, NULL, SYMBOL_INFO" CAL0 Info", _create_mbox_cal0);
554
555
lv_obj_t *desc = lv_cont_create(win, NULL);
556
lv_obj_set_size(desc, LV_HOR_RES / 2 / 5 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
557
558
lv_obj_t * lb_desc = lv_label_create(desc, NULL);
559
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
560
lv_label_set_recolor(lb_desc, true);
561
lv_label_set_style(lb_desc, &monospace_text);
562
563
char version[32];
564
s_printf(version, "%s%d.%d.%d%c", NYX_VER_RL ? "v" : "", NYX_VER_MJ, NYX_VER_MN, NYX_VER_HF, NYX_VER_RL > 'a' ? NYX_VER_RL : 0);
565
lv_obj_t * lbl_ver = lv_label_create(lv_scr_act(), NULL);
566
lv_label_set_style(lbl_ver, &hint_small_style_white);
567
lv_label_set_text(lbl_ver, version);
568
lv_obj_align(lbl_ver, status_bar.bar_bg, LV_ALIGN_OUT_TOP_RIGHT, -LV_DPI * 9 / 23, -LV_DPI * 2 / 13);
569
570
hw_info = zalloc(sizeof(hw_info_t));
571
hw_info->ver = lbl_ver;
572
573
lv_label_set_static_text(lb_desc,
574
"#FF8000 SoC:#\n"
575
"#FF8000 SKU:#\n"
576
"#FF8000 DRAM ID:#\n"
577
"#FF8000 Burnt Fuses (ODM 7/6):#\n"
578
"ODM Fields (4/6/7):\n"
579
"Secure Boot Key (SBK):\n"
580
"Device Key (DK):\n"
581
"Public Key (PK SHA256):\n\n"
582
"HOS Keygen Revision:\n"
583
"USB Controller (BROM):\n"
584
"Final Test Revision:\n"
585
"Chip Probing Revision:\n"
586
"BootROM Revision:\n\n"
587
"#FF8000 CPU/GPU/SoC Speedo:#\n"
588
"CPU/GPU/SoC IDDQ:\n"
589
"CPU Speedo 1:\n"
590
"SoC Speedo 2:\n\n"
591
"Product Code:\n"
592
"Vendor Code:\n"
593
"FAB/LOT Code:\n"
594
"Wafer ID:\n"
595
"X Coordinate:\n"
596
"Y Coordinate:\n\n"
597
"Uptime:"
598
);
599
600
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
601
602
lv_obj_t *val = lv_cont_create(win, NULL);
603
lv_obj_set_size(val, LV_HOR_RES / 7 * 2 + LV_DPI / 11, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
604
605
lv_obj_t * lb_val = lv_label_create(val, lb_desc);
606
607
char *txt_buf = (char *)malloc(SZ_16K);
608
609
// Decode fuses.
610
char *sku;
611
char dram_model[64];
612
char fuses_hos_version[64];
613
u8 dram_id = fuse_read_dramid(true);
614
u8 dram_id_adj = fuse_read_dramid(false);
615
616
switch (fuse_read_hw_type())
617
{
618
case FUSE_NX_HW_TYPE_ICOSA:
619
sku = "Icosa - Odin";
620
break;
621
case FUSE_NX_HW_TYPE_IOWA:
622
sku = "Iowa - Modin";
623
break;
624
case FUSE_NX_HW_TYPE_HOAG:
625
sku = "Hoag - Vali";
626
break;
627
case FUSE_NX_HW_TYPE_AULA:
628
sku = "Aula - Fric";
629
break;
630
default:
631
sku = "#FF8000 Unknown#";
632
break;
633
}
634
635
// Prepare dram id info.
636
if (!h_cfg.t210b01)
637
{
638
switch (dram_id)
639
{
640
// LPDDR4 3200Mbps.
641
case LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH:
642
strcpy(dram_model, "Samsung K4F6E304HB-MGCH 4GB");
643
break;
644
case LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE:
645
strcpy(dram_model, "Hynix H9HCNNNBPUMLHR-NLE 4GB");
646
break;
647
case LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC:
648
strcpy(dram_model, "Micron MT53B512M32D2NP-062 WT:C");
649
break;
650
case LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH:
651
strcpy(dram_model, "Samsung K4FHE3D4HM-MGCH 6GB");
652
break;
653
case LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX:
654
strcpy(dram_model, "Samsung K4FBE3D4HM-MGXX 8GB");
655
break;
656
default:
657
strcpy(dram_model, "#FF8000 Unknown#");
658
break;
659
}
660
}
661
else
662
{
663
switch (dram_id)
664
{
665
// LPDDR4X 3733Mbps.
666
case LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ:
667
case LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ:
668
strcpy(dram_model, "Samsung K4U6E3S4AM-MGCJ 4GB");
669
break;
670
case LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ:
671
case LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ:
672
strcpy(dram_model, "Samsung K4UBE3D4AM-MGCJ 8GB");
673
break;
674
case LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME:
675
case LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME:
676
strcpy(dram_model, "Hynix H9HCNNNBKMMLHR-NME 4GB");
677
break;
678
case LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE: // 4266Mbps.
679
case LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE: // 4266Mbps.
680
strcpy(dram_model, "Micron MT53E512M32D2NP-046 WT:E");
681
break;
682
683
// LPDDR4X 4266Mbps
684
case LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL:
685
case LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL:
686
case LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL:
687
strcpy(dram_model, "Samsung K4U6E3S4AA-MGCL 4GB");
688
break;
689
case LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL:
690
case LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL:
691
case LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL:
692
strcpy(dram_model, "Samsung K4UBE3D4AA-MGCL 8GB");
693
break;
694
case LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL:
695
case LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL:
696
case LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL:
697
strcpy(dram_model, "Samsung K4U6E3S4AB-MGCL 4GB");
698
break;
699
case LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF:
700
case LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF:
701
case LPDDR4X_AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF:
702
strcpy(dram_model, "Micron MT53E512M32D2NP-046 WT:F");
703
break;
704
case LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE: // Replaced from Copper.
705
case LPDDR4X_AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE: // Replaced from Copper.
706
case LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE: // Replaced from Copper.
707
strcpy(dram_model, "Hynix H9HCNNNBKMMLXR-NEE 4GB");
708
break;
709
case LPDDR4X_IOWA_4GB_HYNIX_H54G46CYRBX267:
710
case LPDDR4X_HOAG_4GB_HYNIX_H54G46CYRBX267:
711
case LPDDR4X_AULA_4GB_HYNIX_H54G46CYRBX267:
712
strcpy(dram_model, "Hynix H54G46CYRBX267 4GB");
713
break;
714
case LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB:
715
case LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB:
716
case LPDDR4X_AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB:
717
strcpy(dram_model, "Micron MT53E512M32D1NP-046 WT:B");
718
break;
719
720
default:
721
strcpy(dram_model, "#FF8000 Contact me!#");
722
break;
723
}
724
}
725
726
// Check if DRAM config is forced to 8GB.
727
if (dram_id != dram_id_adj &&
728
((!h_cfg.t210b01 && dram_id_adj == LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX) ||
729
( h_cfg.t210b01 && dram_id_adj == LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL))
730
)
731
strcpy(dram_model, "#FF8000 Forced DRAM Config 8GB#");
732
733
// Count burnt fuses.
734
u8 burnt_fuses_7 = bit_count(fuse_read_odm(7));
735
u8 burnt_fuses_6 = bit_count(fuse_read_odm(6));
736
737
// Check if overburnt.
738
u8 burnt_fuses_hos = (fuse_read_odm(7) & ~bit_count_mask(burnt_fuses_7)) ? 255 : burnt_fuses_7;
739
740
//! TODO: Update on anti-downgrade fuses change.
741
switch (burnt_fuses_hos)
742
{
743
case 0:
744
strcpy(fuses_hos_version, "#96FF00 Golden sample#");
745
break;
746
case 1:
747
strcpy(fuses_hos_version, "1.0.0");
748
break;
749
case 2:
750
strcpy(fuses_hos_version, "2.0.0 - 2.3.0");
751
break;
752
case 3:
753
strcpy(fuses_hos_version, "3.0.0");
754
break;
755
case 4:
756
strcpy(fuses_hos_version, "3.0.1 - 3.0.2");
757
break;
758
case 5:
759
strcpy(fuses_hos_version, "4.0.0 - 4.1.0");
760
break;
761
case 6:
762
strcpy(fuses_hos_version, "5.0.0 - 5.1.0");
763
break;
764
case 7:
765
strcpy(fuses_hos_version, "6.0.0 - 6.1.0");
766
break;
767
case 8:
768
strcpy(fuses_hos_version, "6.2.0");
769
break;
770
case 9:
771
strcpy(fuses_hos_version, "7.0.0 - 8.0.1");
772
break;
773
case 10:
774
strcpy(fuses_hos_version, "8.1.0 - 8.1.1");
775
break;
776
case 11:
777
strcpy(fuses_hos_version, "9.0.0 - 9.0.1");
778
break;
779
case 12:
780
strcpy(fuses_hos_version, "9.1.0 - 9.2.0");
781
break;
782
case 13:
783
strcpy(fuses_hos_version, "10.0.0 - 10.2.0");
784
break;
785
case 14:
786
strcpy(fuses_hos_version, "11.0.0 - 12.0.1");
787
break;
788
case 15:
789
strcpy(fuses_hos_version, "12.0.2 - 13.2.0");
790
break;
791
case 16:
792
strcpy(fuses_hos_version, "13.2.1 - 14.1.2");
793
break;
794
case 17:
795
strcpy(fuses_hos_version, "15.0.0 - 15.0.1");
796
break;
797
case 18:
798
strcpy(fuses_hos_version, "16.0.0 - 16.1.0");
799
break;
800
case 19:
801
strcpy(fuses_hos_version, "17.0.0 - 18.1.0");
802
break;
803
case 20:
804
strcpy(fuses_hos_version, "19.0.0 - 19.0.1");
805
break;
806
case 21:
807
strcpy(fuses_hos_version, "20.0.0 - 20.5.0");
808
break;
809
case 22:
810
strcpy(fuses_hos_version, "21.0.0 - 21.2.0");
811
break;
812
case 23:
813
strcpy(fuses_hos_version, "22.0.0+");
814
break;
815
case 255:
816
strcpy(fuses_hos_version, "#FFD000 Overburnt#");
817
break;
818
default:
819
strcpy(fuses_hos_version, "#FF8000 Unknown#");
820
break;
821
}
822
823
u32 fab = FUSE(FUSE_OPT_FAB_CODE);
824
825
// Convert LOT from base36 BCD to binary.
826
u32 lot_enc = FUSE(FUSE_OPT_LOT_CODE_0);
827
u32 lot_dec = 0;
828
char lot_bcd[6] = {0};
829
830
for (int i = 0; i < 5; ++i)
831
{
832
u32 digit = (lot_enc & 0x3F000000) >> 24;
833
lot_dec *= 36;
834
lot_dec += digit;
835
lot_enc <<= 6;
836
lot_bcd[i] = base36[digit];
837
}
838
839
char sbk_key[64];
840
char dev_key[32];
841
if (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF &&
842
FUSE(FUSE_PRIVATE_KEY1) == 0xFFFFFFFF &&
843
FUSE(FUSE_PRIVATE_KEY2) == 0xFFFFFFFF &&
844
FUSE(FUSE_PRIVATE_KEY3) == 0xFFFFFFFF &&
845
FUSE(FUSE_PRIVATE_KEY4) == 0xFFFFFFFF)
846
{
847
strcpy(sbk_key, "Can't be read (locked out)");
848
strcpy(dev_key, "Can't be read (locked out)");
849
}
850
else
851
{
852
s_printf(sbk_key, "%08X%08X%08X%08X",
853
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
854
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
855
s_printf(dev_key, "%08X", byte_swap_32(FUSE(FUSE_PRIVATE_KEY4)));
856
}
857
858
u32 chip_id = APB_MISC(APB_MISC_GP_HIDREV);
859
u32 chip_major = (chip_id >> 4) & 0xF;
860
u32 chip_minor = (chip_id >> 16) & 0xF;
861
char *chip_name = !h_cfg.t210b01 ? "T210 (Erista)" : "T210B01 (Mariko)";
862
863
u32 brom_rev = FUSE(FUSE_SOC_SPEEDO_1_CALIB);
864
u32 prod_rev = !h_cfg.t210b01 ? (brom_rev < 0x7F ? 1 : 2) : 10;
865
char product_part[16];
866
s_printf(product_part, "ODNX%02d-A%d", prod_rev, chip_minor);
867
868
char iddq[3][8];
869
s_printf(iddq[0], "%d", FUSE(FUSE_CPU_IDDQ_CALIB) * 4);
870
s_printf(iddq[1], "%d", FUSE(FUSE_GPU_IDDQ_CALIB) * 5);
871
s_printf(iddq[2], "%d", FUSE(FUSE_SOC_IDDQ_CALIB) * 4);
872
873
int die_x = FUSE(FUSE_OPT_X_COORDINATE);
874
int die_y = FUSE(FUSE_OPT_Y_COORDINATE);
875
876
// X Coordinate is 9-bit 2s complement.
877
die_x = (die_x & BIT(8)) ? (die_x - 512) : die_x;
878
879
// Render the wafer.
880
_hw_info_wafer(die_x, die_y);
881
882
// Parse fuses and display them.
883
s_printf(txt_buf,
884
"%02X - %s - M%d A%02d\n"
885
"%X - %s - %s\n"
886
"%02d - %s\n"
887
"%d | %d - HOS: %s\n"
888
"%08X %08X %08X\n"
889
"%s\n%s\n"
890
"%08X%08X%08X%08X\n"
891
"%08X%08X%08X%08X\n"
892
"%d\n"
893
"%s\n"
894
"%d.%02d (0x%X)\n"
895
"%d.%02d (0x%X)\n"
896
"0x%X\n\n"
897
"%4d %4d %4d\n"
898
"%.4s %.4s %.4s\n"
899
"%d\n%d\n\n"
900
"%s\n%d\n%c%s (%d/%d)\n"
901
"%d\n%d\n%d\n\n"
902
"%dh %02dm %02ds",
903
(chip_id >> 8) & 0xFF, chip_name, chip_major, chip_minor,
904
FUSE(FUSE_SKU_INFO), sku, fuse_read_hw_state() ? "Dev" : "Retail",
905
dram_id, dram_model,
906
burnt_fuses_7, burnt_fuses_6, fuses_hos_version,
907
fuse_read_odm(4), fuse_read_odm(6), fuse_read_odm(7),
908
sbk_key, dev_key,
909
byte_swap_32(FUSE(FUSE_PUBLIC_KEY0)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY1)),
910
byte_swap_32(FUSE(FUSE_PUBLIC_KEY2)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY3)),
911
byte_swap_32(FUSE(FUSE_PUBLIC_KEY4)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY5)),
912
byte_swap_32(FUSE(FUSE_PUBLIC_KEY6)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY7)),
913
fuse_read_odm_keygen_rev(),
914
((FUSE(FUSE_RESERVED_SW) & 0x80) || h_cfg.t210b01) ? "XUSB" : "USB2",
915
(FUSE(FUSE_OPT_FT_REV) >> 5) & 0x3F, FUSE(FUSE_OPT_FT_REV) & 0x1F, FUSE(FUSE_OPT_FT_REV),
916
(FUSE(FUSE_OPT_CP_REV) >> 5) & 0x3F, FUSE(FUSE_OPT_CP_REV) & 0x1F, FUSE(FUSE_OPT_CP_REV),
917
brom_rev,
918
FUSE(FUSE_CPU_SPEEDO_0_CALIB), FUSE(FUSE_CPU_SPEEDO_2_CALIB), FUSE(FUSE_SOC_SPEEDO_0_CALIB),
919
iddq[0], iddq[1], iddq[2],
920
FUSE(FUSE_CPU_SPEEDO_1_CALIB), FUSE(FUSE_SOC_SPEEDO_2_CALIB),
921
product_part, FUSE(FUSE_OPT_VENDOR_CODE), base36[fab], lot_bcd, fab, lot_dec,
922
FUSE(FUSE_OPT_WAFER_ID), die_x, die_y,
923
uptime_s / 3600, (uptime_s / 60) % 60, uptime_s % 60);
924
925
lv_label_set_text(lb_val, txt_buf);
926
927
lv_obj_set_width(lb_val, lv_obj_get_width(val));
928
lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
929
930
lv_obj_t *desc2 = lv_cont_create(win, NULL);
931
lv_obj_set_size(desc2, LV_HOR_RES / 2 / 5 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
932
933
lv_obj_t * lb_desc2 = lv_label_create(desc2, NULL);
934
lv_label_set_long_mode(lb_desc2, LV_LABEL_LONG_BREAK);
935
lv_label_set_recolor(lb_desc2, true);
936
937
// Prepare DRAM info.
938
emc_mr_data_t ram_vendor = sdram_read_mrx(MR5_MAN_ID);
939
emc_mr_data_t ram_rev0 = sdram_read_mrx(MR6_REV_ID1);
940
emc_mr_data_t ram_rev1 = sdram_read_mrx(MR7_REV_ID2);
941
emc_mr_data_t ram_density = sdram_read_mrx(MR8_DENSITY);
942
u32 ranks = EMC(EMC_ADR_CFG) + 1;
943
u32 channels = (EMC(EMC_FBIO_CFG7) >> 1) & 3;
944
channels = (channels & 1) + ((channels & 2) >> 1);
945
s_printf(txt_buf, "#00DDFF %s SDRAM ##FF8000 (Module 0 | 1):#\n#FF8000 Vendor:# ", h_cfg.t210b01 ? "LPDDR4X" : "LPDDR4");
946
switch (ram_vendor.chip0.rank0_ch0)
947
{
948
case 1:
949
strcat(txt_buf, "Samsung");
950
break;
951
/*
952
case 5:
953
strcat(txt_buf, "Nanya");
954
break;
955
*/
956
case 6:
957
strcat(txt_buf, "Hynix");
958
break;
959
/*
960
case 8:
961
strcat(txt_buf, "Winbond");
962
break;
963
case 9:
964
strcat(txt_buf, "ESMT");
965
break;
966
case 19:
967
strcat(txt_buf, "CXMT");
968
break;
969
case 26:
970
strcat(txt_buf, "Xi'an UniIC");
971
break;
972
case 27:
973
strcat(txt_buf, "ISSI");
974
break;
975
case 28:
976
strcat(txt_buf, "JSC");
977
break;
978
case 197:
979
strcat(txt_buf, "SINKER");
980
break;
981
case 229:
982
strcat(txt_buf, "Dosilicon");
983
break;
984
case 248:
985
strcat(txt_buf, "Fidelix");
986
break;
987
case 249:
988
strcat(txt_buf, "Ultra Memory");
989
break;
990
case 253:
991
strcat(txt_buf, "AP Memory");
992
break;
993
*/
994
case 255:
995
strcat(txt_buf, "Micron");
996
break;
997
default:
998
s_printf(txt_buf + strlen(txt_buf), "#FF8000 Unknown# (%d)", ram_vendor.chip0.rank0_ch0);
999
break;
1000
}
1001
strcat(txt_buf, " #FF8000 |# ");
1002
switch (ram_vendor.chip1.rank0_ch0)
1003
{
1004
case 1:
1005
strcat(txt_buf, "Samsung");
1006
break;
1007
case 6:
1008
strcat(txt_buf, "Hynix");
1009
break;
1010
case 255:
1011
strcat(txt_buf, "Micron");
1012
break;
1013
default:
1014
s_printf(txt_buf + strlen(txt_buf), "#FF8000 Unknown# (%d)", ram_vendor.chip1.rank0_ch0);
1015
break;
1016
}
1017
1018
s_printf(txt_buf + strlen(txt_buf), "\n#FF8000 Rev ID:# %X.%02X #FF8000 |# %X.%02X\n#FF8000 Density:# ",
1019
ram_rev0.chip0.rank0_ch0, ram_rev1.chip0.rank0_ch0, ram_rev0.chip1.rank0_ch0, ram_rev1.chip1.rank0_ch0);
1020
1021
u32 actual_ranks = (ram_vendor.chip0.rank0_ch0 == ram_vendor.chip0.rank1_ch0 &&
1022
ram_vendor.chip0.rank0_ch1 == ram_vendor.chip0.rank1_ch1 &&
1023
ram_rev0.chip0.rank0_ch0 == ram_rev0.chip0.rank1_ch0 &&
1024
ram_rev0.chip0.rank0_ch1 == ram_rev0.chip0.rank1_ch1 &&
1025
ram_rev1.chip0.rank0_ch0 == ram_rev1.chip0.rank1_ch0 &&
1026
ram_rev1.chip0.rank0_ch1 == ram_rev1.chip0.rank1_ch1 &&
1027
ram_density.chip0.rank0_ch0 == ram_density.chip0.rank1_ch0 &&
1028
ram_density.chip0.rank0_ch1 == ram_density.chip0.rank1_ch1)
1029
? 2 : 1;
1030
bool rank_bad = ranks != actual_ranks;
1031
s_printf(txt_buf + strlen(txt_buf), "%s %d x %s", rank_bad ? "#FFDD00" : "", actual_ranks * channels, rank_bad ? "#" : "");
1032
1033
switch ((ram_density.chip0.rank0_ch0 & 0x3C) >> 2)
1034
{
1035
case 2:
1036
strcat(txt_buf, "512MB");
1037
break;
1038
case 3:
1039
strcat(txt_buf, "768MB");
1040
break;
1041
case 4:
1042
strcat(txt_buf, "1GB");
1043
break;
1044
case 5:
1045
strcat(txt_buf, "1.5GB");
1046
break;
1047
case 6:
1048
strcat(txt_buf, "2GB");
1049
break;
1050
default:
1051
s_printf(txt_buf + strlen(txt_buf), "Unk (%d)", (ram_density.chip0.rank0_ch0 & 0x3C) >> 2);
1052
break;
1053
}
1054
1055
actual_ranks = (ram_vendor.chip1.rank0_ch0 == ram_vendor.chip1.rank1_ch0 &&
1056
ram_vendor.chip1.rank0_ch1 == ram_vendor.chip1.rank1_ch1 &&
1057
ram_rev0.chip1.rank0_ch0 == ram_rev0.chip1.rank1_ch0 &&
1058
ram_rev0.chip1.rank0_ch1 == ram_rev0.chip1.rank1_ch1 &&
1059
ram_rev1.chip1.rank0_ch0 == ram_rev1.chip1.rank1_ch0 &&
1060
ram_rev1.chip1.rank0_ch1 == ram_rev1.chip1.rank1_ch1 &&
1061
ram_density.chip1.rank0_ch0 == ram_density.chip1.rank1_ch0 &&
1062
ram_density.chip1.rank0_ch1 == ram_density.chip1.rank1_ch1)
1063
? 2 : 1;
1064
rank_bad = ranks != actual_ranks;
1065
1066
s_printf(txt_buf + strlen(txt_buf), " #FF8000 |# %s %d x %s", rank_bad ? "#FFDD00" : "", actual_ranks * channels, rank_bad ? "#" : "");
1067
1068
switch ((ram_density.chip1.rank0_ch0 & 0x3C) >> 2)
1069
{
1070
case 2:
1071
strcat(txt_buf, "512MB");
1072
break;
1073
case 3:
1074
strcat(txt_buf, "768MB");
1075
break;
1076
case 4:
1077
strcat(txt_buf, "1GB");
1078
break;
1079
case 5:
1080
strcat(txt_buf, "1.5GB");
1081
break;
1082
case 6:
1083
strcat(txt_buf, "2GB");
1084
break;
1085
default:
1086
s_printf(txt_buf + strlen(txt_buf), "Unk (%d)", (ram_density.chip1.rank0_ch0 & 0x3C) >> 2);
1087
break;
1088
}
1089
strcat(txt_buf, "\n\n");
1090
1091
// Prepare display info.
1092
u8 display_rev = (nyx_str->info.panel_id >> 8) & 0xFF;
1093
u32 display_id = ((nyx_str->info.panel_id >> 8) & 0xFF00) | (nyx_str->info.panel_id & 0xFF);
1094
1095
// For OLED LCD 7" OEM clone use touch to identify it.
1096
touch_info_t *touch_info = touch_get_chip_info();
1097
bool touch_clone_oled = touch_info->chip_id == FTS4_I2C_CHIP_ID && touch_info->clone;
1098
if (touch_clone_oled)
1099
display_id = 0x10000;
1100
1101
strcat(txt_buf, "#00DDFF Display Panel:#\n#FF8000 Model:# ");
1102
1103
switch (display_id)
1104
{
1105
case PANEL_JDI_LAM062M109A:
1106
strcat(txt_buf, "JDI LAM062M109A");
1107
break;
1108
1109
case PANEL_JDI_LPM062M326A:
1110
strcat(txt_buf, "JDI LPM062M326A");
1111
break;
1112
1113
case PANEL_INL_P062CCA_AZ1:
1114
strcat(txt_buf, "InnoLux P062CCA");
1115
switch (display_rev)
1116
{
1117
case 0x93:
1118
strcat(txt_buf, "-AZ1");
1119
break;
1120
case 0x95:
1121
strcat(txt_buf, "-AZ2");
1122
break;
1123
case 0x96:
1124
strcat(txt_buf, "-AZ3");
1125
break;
1126
case 0x97:
1127
strcat(txt_buf, "-???");
1128
break;
1129
case 0x98:
1130
strcat(txt_buf, "-???");
1131
break;
1132
case 0x99:
1133
strcat(txt_buf, "-???");
1134
break;
1135
default:
1136
strcat(txt_buf, " #FFDD00 Contact me!#");
1137
break;
1138
}
1139
break;
1140
1141
case PANEL_AUO_A062TAN01:
1142
strcat(txt_buf, "AUO A062TAN");
1143
switch (display_rev)
1144
{
1145
case 0x93:
1146
strcat(txt_buf, "00");
1147
break;
1148
case 0x94:
1149
strcat(txt_buf, "01");
1150
break;
1151
case 0x95:
1152
strcat(txt_buf, "02");
1153
break;
1154
case 0x96:
1155
strcat(txt_buf, "??");
1156
break;
1157
case 0x97:
1158
strcat(txt_buf, "??");
1159
break;
1160
case 0x98:
1161
strcat(txt_buf, "??");
1162
break;
1163
default:
1164
strcat(txt_buf, " #FFDD00 Contact me!#");
1165
break;
1166
}
1167
break;
1168
1169
case PANEL_INL_2J055IA_27A:
1170
strcat(txt_buf, "InnoLux 2J055IA-27A");
1171
break;
1172
1173
case PANEL_AUO_A055TAN01:
1174
strcat(txt_buf, "AUO A055TAN");
1175
s_printf(txt_buf + strlen(txt_buf), "%02d", display_rev - 0x92);
1176
break;
1177
1178
case PANEL_SHP_LQ055T1SW10:
1179
strcat(txt_buf, "Sharp LQ055T1SW10");
1180
break;
1181
1182
case PANEL_SAM_AMS699VC01:
1183
strcat(txt_buf, "Samsung AMS699VC01");
1184
break;
1185
1186
case PANEL_OEM_CLONE_6_2:
1187
strcat(txt_buf, "#FFDD00 OEM Clone 6.2\"#");
1188
break;
1189
1190
case PANEL_OEM_CLONE_5_5:
1191
strcat(txt_buf, "#FFDD00 OEM Clone 5.5\"#");
1192
break;
1193
1194
case PANEL_OEM_CLONE:
1195
strcat(txt_buf, "#FFDD00 OEM Clone#");
1196
break;
1197
1198
case 0xCCCC:
1199
strcat(txt_buf, "#FFDD00 Failed to get info!#");
1200
break;
1201
1202
case 0x10000: // Custom ID for LCD OEM Clone for Switch OLED.
1203
strcat(txt_buf, "#FFDD00 LCD OEM Clone 7\"#");
1204
break;
1205
1206
default:
1207
switch (display_id & 0xFF)
1208
{
1209
case PANEL_JDI_XXX062M:
1210
strcat(txt_buf, "JDI ");
1211
break;
1212
case (PANEL_INL_P062CCA_AZ1 & 0xFF):
1213
strcat(txt_buf, "InnoLux ");
1214
break;
1215
case (PANEL_AUO_A062TAN01 & 0xFF):
1216
strcat(txt_buf, "AUO ");
1217
break;
1218
case (PANEL_SAM_AMS699VC01 & 0xFF):
1219
strcat(txt_buf, "Samsung ");
1220
break;
1221
}
1222
strcat(txt_buf, "Unknown #FFDD00 Contact me!#");
1223
break;
1224
}
1225
1226
s_printf(txt_buf + strlen(txt_buf), "\n#FF8000 ID:# #96FF00 %02X# %02X #96FF00 %02X#",
1227
nyx_str->info.panel_id & 0xFF, (nyx_str->info.panel_id >> 8) & 0xFF, (nyx_str->info.panel_id >> 16) & 0xFF);
1228
1229
// Prepare touch panel/ic info.
1230
touch_fw_info_t touch_fw;
1231
if (!touch_get_fw_info(&touch_fw))
1232
{
1233
strcat(txt_buf, "\n\n#00DDFF Touch Panel:#\n#FF8000 Model:# ");
1234
1235
touch_panel_info_t *touch_panel = touch_get_panel_vendor();
1236
if (touch_clone_oled)
1237
strcat(txt_buf, "#FFDD00 OEM Clone TSP#");
1238
else if (touch_panel)
1239
{
1240
if ((u8)touch_panel->idx == (u8)-2) // Touch panel not found, print gpios.
1241
{
1242
s_printf(txt_buf + strlen(txt_buf), "%2X%2X%2X #FFDD00 Contact me!#",
1243
touch_panel->gpio0, touch_panel->gpio1, touch_panel->gpio2);
1244
touch_panel = NULL;
1245
}
1246
else
1247
strcat(txt_buf, touch_panel->vendor);
1248
}
1249
else
1250
strcat(txt_buf, "#FFDD00 Error!#");
1251
1252
s_printf(txt_buf + strlen(txt_buf), "\n#FF8000 ID:# %02X.%02X.%02X.%02X (",
1253
(touch_fw.fw_id >> 24) & 0xFF, (touch_fw.fw_id >> 16) & 0xFF, (touch_fw.fw_id >> 8) & 0xFF, touch_fw.fw_id & 0xFF);
1254
1255
if (touch_clone_oled)
1256
touch_fw.fw_id = 0xFFFFFFFF;
1257
1258
// Check panel pair info.
1259
bool panel_ic_paired = false;
1260
switch (touch_fw.fw_id)
1261
{
1262
case 0x00100100:
1263
strcat(txt_buf, "4CD60D/0");
1264
if (touch_panel)
1265
panel_ic_paired = (u8)touch_panel->idx == (u8)-1;
1266
break;
1267
1268
case 0x00100200: // 4CD 1602.
1269
case 0x00120100:
1270
case 0x32000001:
1271
strcat(txt_buf, "4CD60D/1");
1272
if (touch_panel)
1273
panel_ic_paired = touch_panel->idx == 0; // NISSHA NFT-K12D.
1274
break;
1275
1276
// case 0x98000004: // New 6.2" panel?
1277
// case 0x50000001:
1278
// case 0x50000002:
1279
// strcat(txt_buf, "FST2 UNK");
1280
// if (touch_panel)
1281
// panel_ic_paired = touch_panel->idx == 0;
1282
// break;
1283
1284
case 0x001A0300:
1285
case 0x32000102:
1286
strcat(txt_buf, "4CD60D/2");
1287
if (touch_panel)
1288
panel_ic_paired = touch_panel->idx == 1; // GiS GGM6 B2X.
1289
break;
1290
1291
case 0x00290100:
1292
case 0x32000302:
1293
strcat(txt_buf, "4CD60D/3");
1294
if (touch_panel)
1295
panel_ic_paired = touch_panel->idx == 2; // NISSHA NBF-K9A.
1296
break;
1297
1298
case 0x31051820:
1299
case 0x32000402:
1300
strcat(txt_buf, "4CD60D/4");
1301
if (touch_panel)
1302
panel_ic_paired = touch_panel->idx == 3; // GiS 5.5".
1303
break;
1304
1305
case 0x32000501:
1306
case 0x33000502:
1307
case 0x33000503:
1308
case 0x33000510:
1309
strcat(txt_buf, "4CD60D/5");
1310
if (touch_panel)
1311
panel_ic_paired = touch_panel->idx == 4; // Samsung BH2109.
1312
break;
1313
1314
case 0xFFFFFFFF: // Custom for OLED clone.
1315
strcat(txt_buf, "Clone");
1316
panel_ic_paired = true;
1317
break;
1318
1319
default:
1320
strcat(txt_buf, "#FF8000 Contact me#");
1321
break;
1322
}
1323
1324
s_printf(txt_buf + strlen(txt_buf), " - %s)\n#FF8000 FTB ver:# %04X\n#FF8000 FW rev:# %04X",
1325
panel_ic_paired ? "Paired" : "#FFDD00 Error#",
1326
touch_fw.ftb_ver,
1327
byte_swap_16(touch_fw.fw_rev)); // Byte swapping makes more sense here.
1328
}
1329
else
1330
strcat(txt_buf, "\n\n#FFDD00 Failed to get touch info!#");
1331
1332
// Check if patched unit.
1333
if (!fuse_check_patched_rcm())
1334
strcat(txt_buf, "\n\n#96FF00 This unit is exploitable#\n#96FF00 to the RCM bug!#");
1335
else
1336
strcat(txt_buf, "\n\n#FF8000 This unit is patched#\n#FF8000 to the RCM bug!#");
1337
1338
lv_label_set_text(lb_desc2, txt_buf);
1339
1340
free(txt_buf);
1341
1342
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
1343
lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 4, 0);
1344
1345
return LV_RES_OK;
1346
}
1347
1348
static char *ipatches_txt;
1349
static void _ipatch_process(u32 offset, u32 value)
1350
{
1351
s_printf(ipatches_txt + strlen(ipatches_txt), "%6X %4X ", IROM_BASE + offset, value);
1352
u8 lo = value & 0xFF;
1353
switch (value >> 8)
1354
{
1355
case 0x20:
1356
s_printf(ipatches_txt + strlen(ipatches_txt), "MOVS R0, ##0x%02X", lo);
1357
break;
1358
case 0x21:
1359
s_printf(ipatches_txt + strlen(ipatches_txt), "MOVS R1, ##0x%02X", lo);
1360
break;
1361
case 0xDF:
1362
s_printf(ipatches_txt + strlen(ipatches_txt), "SVC ##0x%02X", lo);
1363
break;
1364
}
1365
strcat(ipatches_txt, "\n");
1366
}
1367
1368
static lv_res_t _create_window_bootrom_info_status(lv_obj_t *btn)
1369
{
1370
lv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP" Bootrom Info", NULL);
1371
lv_win_add_btn(win, NULL, SYMBOL_DOWNLOAD" Dump Bootrom", _bootrom_dump_window_action);
1372
1373
lv_obj_t *desc = lv_cont_create(win, NULL);
1374
lv_obj_set_size(desc, LV_HOR_RES / 2 / 3 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
1375
1376
lv_obj_t * lb_desc = lv_label_create(desc, NULL);
1377
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
1378
lv_label_set_recolor(lb_desc, true);
1379
lv_label_set_style(lb_desc, &monospace_text);
1380
1381
char *txt_buf = (char *)malloc(SZ_4K);
1382
ipatches_txt = txt_buf;
1383
s_printf(txt_buf, "#00DDFF Ipatches:#\n#FF8000 Address "SYMBOL_DOT" Val "SYMBOL_DOT" Instruction#\n");
1384
1385
u32 res = fuse_read_ipatch(_ipatch_process);
1386
if (res != 0)
1387
s_printf(txt_buf + strlen(txt_buf), "#FFDD00 Failed to read ipatches. Error: %d#", res);
1388
1389
lv_label_set_text(lb_desc, txt_buf);
1390
1391
free(txt_buf);
1392
1393
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
1394
1395
return LV_RES_OK;
1396
}
1397
1398
static lv_res_t _launch_lockpick_action(lv_obj_t *btns, const char * txt)
1399
{
1400
int btn_idx = lv_btnm_get_pressed(btns);
1401
1402
nyx_mbox_action(btns, txt);
1403
1404
if (btn_idx == 1)
1405
{
1406
lv_obj_t *list = lv_list_create(NULL, NULL);
1407
lv_obj_set_size(list, 1, 1);
1408
lv_list_set_single_mode(list, true);
1409
lv_list_add(list, NULL, "Lockpick_RCM.bin", NULL);
1410
lv_obj_t *btn;
1411
btn = lv_list_get_prev_btn(list, NULL);
1412
launch_payload(btn);
1413
lv_obj_del(list);
1414
}
1415
1416
return LV_RES_INV;
1417
}
1418
1419
static lv_res_t _create_mbox_lockpick(lv_obj_t *btn)
1420
{
1421
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
1422
lv_obj_set_style(dark_bg, &mbox_darken);
1423
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
1424
1425
static const char * mbox_btn_map[] = { "\251", "\222Continue", "\222Close", "\251", "" };
1426
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
1427
lv_mbox_set_recolor_text(mbox, true);
1428
1429
lv_mbox_set_text(mbox, "#FF8000 Lockpick RCM#\n\nThis will launch Lockpick RCM.\nDo you want to continue?\n\n"
1430
"To return back from lockpick use\n#96FF00 Reboot to hekate#.");
1431
1432
lv_mbox_add_btns(mbox, mbox_btn_map, _launch_lockpick_action);
1433
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);
1434
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1435
lv_obj_set_top(mbox, true);
1436
1437
return LV_RES_OK;
1438
}
1439
1440
static lv_res_t _create_mbox_emmc_sandisk_report(lv_obj_t * btn)
1441
{
1442
static lv_style_t h_style;
1443
lv_style_copy(&h_style, &lv_style_transp);
1444
h_style.body.padding.inner = 0;
1445
h_style.body.padding.hor = LV_DPI - (LV_DPI / 4);
1446
h_style.body.padding.ver = LV_DPI / 6;
1447
1448
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
1449
lv_obj_set_style(dark_bg, &mbox_darken);
1450
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
1451
1452
static const char * mbox_btn_map[] = { "\251", "\222Close", "\251", "" };
1453
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
1454
lv_mbox_set_recolor_text(mbox, true);
1455
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 8);
1456
1457
lv_mbox_set_text(mbox, "#C7EA46 Sandisk Device Report#");
1458
1459
u8 *buf = zalloc(EMMC_BLOCKSIZE);
1460
char *txt_buf = (char *)malloc(SZ_32K);
1461
char *txt_buf2 = (char *)malloc(SZ_32K);
1462
txt_buf[0] = 0;
1463
txt_buf2[0] = 0;
1464
1465
// Create SoC Info container.
1466
lv_obj_t *h1 = lv_cont_create(mbox, NULL);
1467
lv_cont_set_style(h1, &h_style);
1468
lv_cont_set_fit(h1, false, true);
1469
lv_obj_set_width(h1, (LV_HOR_RES / 9) * 7);
1470
lv_obj_set_click(h1, false);
1471
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
1472
1473
lv_obj_t * lb_desc = lv_label_create(h1, NULL);
1474
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
1475
lv_label_set_recolor(lb_desc, true);
1476
lv_label_set_style(lb_desc, &monospace_text);
1477
lv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4);
1478
1479
lv_obj_t * lb_desc2 = lv_label_create(h1, NULL);
1480
lv_label_set_long_mode(lb_desc2, LV_LABEL_LONG_BREAK);
1481
lv_label_set_recolor(lb_desc2, true);
1482
lv_label_set_style(lb_desc2, &monospace_text);
1483
lv_obj_set_width(lb_desc2, LV_HOR_RES / 9 * 3);
1484
lv_obj_align(lb_desc2, lb_desc, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);
1485
1486
1487
if (emmc_initialize(false))
1488
{
1489
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
1490
1491
goto out;
1492
}
1493
1494
int res = sdmmc_storage_vendor_sandisk_report(&emmc_storage, buf);
1495
emmc_end();
1496
1497
if (res)
1498
{
1499
lv_label_set_text(lb_desc, "#FFDD00 Device Report not supported!#");
1500
lv_label_set_text(lb_desc2, " ");
1501
1502
goto out;
1503
}
1504
1505
mmc_sandisk_report_t *rpt = (mmc_sandisk_report_t *)buf;
1506
1507
u8 fw_update_date[13] = {0};
1508
u8 fw_update_time[9] = {0};
1509
memcpy(fw_update_date, rpt->fw_update_date, sizeof(rpt->fw_update_date));
1510
memcpy(fw_update_time, rpt->fw_update_time, sizeof(rpt->fw_update_time));
1511
1512
s_printf(txt_buf,
1513
"#00DDFF Device report#\n"
1514
//"#FF8000 Average Erases SYS:# %d\n"
1515
"#FF8000 Average Erases SLC:# %d\n"
1516
"#FF8000 Average Erases MLC:# %d\n"
1517
//"#FF8000 Read Reclaims SYS:# %d\n"
1518
"#FF8000 Read Reclaims SLC:# %d\n"
1519
"#FF8000 Read Reclaims MLC:# %d\n"
1520
"#FF8000 Bad Blocks Factory:# %d\n"
1521
"#FF8000 Bad Blocks SYS:# %d\n"
1522
"#FF8000 Bad Blocks SLC:# %d\n"
1523
"#FF8000 Bad Blocks MLC:# %d\n"
1524
"#FF8000 FW Updates:# %d\n"
1525
"#FF8000 FW Buildtime:# %s %s\n"
1526
"#FF8000 Total Writes:# %d MB\n"
1527
//"#FF8000 Voltage Drops:# %d\n"
1528
//"#FF8000 Voltage Droops:# %d\n"
1529
//"#FF8000 VD Failed Recovers:# %d\n"
1530
//"#FF8000 VD Recover Operations:# %d\n"
1531
"#FF8000 Total Writes SLC:# %d MB\n"
1532
"#FF8000 Total Writes MLC:# %d MB\n"
1533
"#FF8000 BigFile limit status:# %d\n"
1534
"#FF8000 Average Erases Hybrid:# %d",
1535
1536
//rpt->avg_erase_cycles_sys,
1537
rpt->avg_erase_cycles_slc,
1538
rpt->avg_erase_cycles_mlc,
1539
//rpt->read_reclaim_cnt_sys,
1540
rpt->read_reclaim_cnt_slc,
1541
rpt->read_reclaim_cnt_mlc,
1542
rpt->bad_blocks_factory,
1543
rpt->bad_blocks_sys,
1544
rpt->bad_blocks_slc,
1545
rpt->bad_blocks_mlc,
1546
rpt->fw_updates_cnt,
1547
fw_update_date,
1548
fw_update_time,
1549
rpt->total_writes_100mb * 100,
1550
//rpt->vdrops,
1551
//rpt->vdroops,
1552
//rpt->vdrops_failed_data_rec,
1553
//rpt->vdrops_data_rec_ops,
1554
rpt->total_writes_slc_100mb * 100,
1555
rpt->total_writes_mlc_100mb * 100,
1556
rpt->mlc_bigfile_mode_limit_exceeded,
1557
rpt->avg_erase_cycles_hybrid);
1558
1559
u8 advanced_report = 0;
1560
for (u32 i = 0; i < sizeof(mmc_sandisk_advanced_report_t); i++)
1561
advanced_report |= *(u8 *)((u8 *)&rpt->advanced + i);
1562
1563
if (advanced_report)
1564
{
1565
s_printf(txt_buf2,
1566
"#00DDFF Advanced Health Status#\n"
1567
"#FF8000 Power ups:# %d\n"
1568
//"#FF8000 Maximum Erases SYS:# %d\n"
1569
"#FF8000 Maximum Erases SLC:# %d\n"
1570
"#FF8000 Maximum Erases MLC:# %d\n"
1571
//"#FF8000 Minimum Erases SYS:# %d\n"
1572
"#FF8000 Minimum Erases SLC:# %d\n"
1573
"#FF8000 Minimum Erases MLC:# %d\n"
1574
"#FF8000 Maximum Erases EUDA:# %d\n"
1575
"#FF8000 Minimum Erases EUDA:# %d\n"
1576
"#FF8000 Average Erases EUDA:# %d\n"
1577
"#FF8000 Read Reclaims EUDA:# %d\n"
1578
"#FF8000 Bad Blocks EUDA:# %d\n"
1579
//"#FF8000 Pre EOL State EUDA:# %d\n"
1580
//"#FF8000 Pre EOL State SYS:# %d\n"
1581
//"#FF8000 Pre EOL State MLC:# %d\n"
1582
"#FF8000 Uncorrectable ECC:# %d\n"
1583
"#FF8000 Temperature Now:# %d oC\n"
1584
//"#FF8000 Temperature Min:# %d oC\n"
1585
"#FF8000 Temperature Max:# %d oC\n"
1586
"#FF8000 Health Level EUDA:# %d%%\n"
1587
//"#FF8000 Health Level SYS:# %d%%\n"
1588
"#FF8000 Health Level MLC:# %d%%",
1589
1590
rpt->advanced.power_inits,
1591
//rpt->advanced.max_erase_cycles_sys,
1592
rpt->advanced.max_erase_cycles_slc,
1593
rpt->advanced.max_erase_cycles_mlc,
1594
//rpt->advanced.min_erase_cycles_sys,
1595
rpt->advanced.min_erase_cycles_slc,
1596
rpt->advanced.min_erase_cycles_mlc,
1597
rpt->advanced.max_erase_cycles_euda,
1598
rpt->advanced.min_erase_cycles_euda,
1599
rpt->advanced.avg_erase_cycles_euda,
1600
rpt->advanced.read_reclaim_cnt_euda,
1601
rpt->advanced.bad_blocks_euda,
1602
//rpt->advanced.pre_eol_euda,
1603
//rpt->advanced.pre_eol_sys,
1604
//rpt->advanced.pre_eol_mlc,
1605
rpt->advanced.uncorrectable_ecc,
1606
rpt->advanced.temperature_now,
1607
//rpt->advanced.temperature_min,
1608
rpt->advanced.temperature_max,
1609
rpt->advanced.health_pct_euda ? 101 - rpt->advanced.health_pct_euda : 0,
1610
//rpt->advanced.health_pct_sys ? 101 - rpt->advanced.health_pct_sys : 0,
1611
rpt->advanced.health_pct_mlc ? 101 - rpt->advanced.health_pct_mlc : 0);
1612
}
1613
else
1614
strcpy(txt_buf2, "#00DDFF Advanced Health Status#\n#FFDD00 Empty!#");
1615
1616
lv_label_set_text(lb_desc, txt_buf);
1617
lv_label_set_text(lb_desc2, txt_buf2);
1618
1619
out:
1620
free(buf);
1621
free (txt_buf);
1622
free (txt_buf2);
1623
1624
lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action); // Important. After set_text.
1625
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1626
lv_obj_set_top(mbox, true);
1627
1628
return LV_RES_OK;
1629
}
1630
1631
static lv_obj_t *bench_sd_err_label = NULL;
1632
1633
static lv_res_t _create_mbox_benchmark(bool sd_bench)
1634
{
1635
sdmmc_storage_t *storage;
1636
1637
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
1638
lv_obj_set_style(dark_bg, &mbox_darken);
1639
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
1640
1641
static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
1642
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
1643
lv_mbox_set_recolor_text(mbox, true);
1644
lv_obj_set_width(mbox, LV_HOR_RES * 3 / 7);
1645
1646
char *txt_buf = (char *)malloc(SZ_16K);
1647
1648
s_printf(txt_buf, "#FF8000 %s Benchmark#\n[Raw Reads] Abort: VOL- & VOL+", sd_bench ? "SD Card" : "eMMC");
1649
1650
lv_mbox_set_text(mbox, txt_buf);
1651
txt_buf[0] = 0;
1652
1653
lv_obj_t *h1 = lv_cont_create(mbox, NULL);
1654
lv_cont_set_fit(h1, false, true);
1655
lv_cont_set_style(h1, &lv_style_transp_tight);
1656
lv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI / 10);
1657
1658
lv_obj_t *lbl_status = lv_label_create(h1, NULL);
1659
lv_label_set_style(lbl_status, &monospace_text);
1660
lv_label_set_recolor(lbl_status, true);
1661
lv_label_set_text(lbl_status, " ");
1662
lv_obj_align(lbl_status, h1, LV_ALIGN_IN_TOP_MID, 0, 0);
1663
1664
lv_obj_t *bar = lv_bar_create(mbox, NULL);
1665
lv_obj_set_size(bar, LV_DPI * 2, LV_DPI / 5);
1666
lv_bar_set_range(bar, 0, 100);
1667
lv_bar_set_value(bar, 0);
1668
1669
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1670
lv_obj_set_top(mbox, true);
1671
manual_system_maintenance(true);
1672
1673
int res = 0;
1674
1675
if (sd_bench)
1676
{
1677
storage = &sd_storage;
1678
1679
// Re-initialize to update trimmers.
1680
sd_end();
1681
res = sd_mount();
1682
}
1683
else
1684
{
1685
storage = &emmc_storage;
1686
res = emmc_initialize(false);
1687
if (!res)
1688
emmc_set_partition(EMMC_GPP);
1689
}
1690
1691
if (res)
1692
{
1693
lv_mbox_set_text(mbox, "#FFDD00 Failed to init Storage!#");
1694
goto out;
1695
}
1696
1697
// Set benchmark parameters.
1698
const u32 sct_blk_seq = 0x8000; // 16MB. A2 spec denotes 4MB, but using older big AU.
1699
const u32 sct_blk_4kb = 8; // 4KB.
1700
const u32 sct_rem_seq = 0x200000; // 1GB. A2 spec.
1701
const u32 sct_rem_4kb = 0x80000; // 256MB. A2 spec.
1702
const u32 sct_num_1mb = 0x800; // 1MB.
1703
const u32 size_bytes_seq = sct_rem_seq * SDMMC_DAT_BLOCKSIZE;
1704
const u32 size_bytes_4kb = sct_rem_4kb * SDMMC_DAT_BLOCKSIZE;
1705
1706
// Set calculation divider. 1000 or 1024. (Does not affect IOPS).
1707
u32 mb_div = 1000; // Unfortunately most software uses fake MB.
1708
1709
char *mbs_text;
1710
switch (mb_div)
1711
{
1712
case 1000:
1713
mbs_text = "MB/s";
1714
break;
1715
case 1024:
1716
mbs_text = "MiB/s";
1717
break;
1718
}
1719
1720
// Set actual div in MB/MiB.
1721
mb_div *= mb_div;
1722
1723
int error = 0;
1724
u32 iters = 3;
1725
u32 offset_chunk_start = ALIGN_DOWN(storage->sec_cnt / 3, sct_blk_seq); // Align to block.
1726
if (storage->sec_cnt < 0xC00000)
1727
iters -= 2; // 4GB card.
1728
1729
u32 rnd_off_cnt = sct_rem_4kb / sct_blk_4kb;
1730
u32 *random_offsets = malloc(rnd_off_cnt * sizeof(u32));
1731
u32 *times_taken_4k = malloc(rnd_off_cnt * sizeof(u32));
1732
1733
for (u32 iter_curr = 0; iter_curr < iters; iter_curr++)
1734
{
1735
u32 pct = 0;
1736
u32 prevPct = 200;
1737
u32 timer = 0;
1738
u32 lba_curr = 0;
1739
u32 sector_off = offset_chunk_start * iter_curr;
1740
u32 sector_num = sct_blk_seq;
1741
u32 data_remaining = sct_rem_seq;
1742
1743
s_printf(txt_buf + strlen(txt_buf), "#C7EA46 %d/3# - Sector Offset #C7EA46 %08X#:\n", iter_curr + 1, sector_off);
1744
1745
u32 render_min_ms = 66;
1746
u32 render_timer = get_tmr_ms() + render_min_ms;
1747
while (data_remaining)
1748
{
1749
u32 time_taken = get_tmr_us();
1750
error = sdmmc_storage_read(storage, sector_off + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);
1751
time_taken = get_tmr_us() - time_taken;
1752
timer += time_taken;
1753
1754
manual_system_maintenance(false);
1755
data_remaining -= sector_num;
1756
lba_curr += sector_num;
1757
1758
pct = (lba_curr * 100) / sct_rem_seq;
1759
if (pct != prevPct && render_timer < get_tmr_ms())
1760
{
1761
lv_bar_set_value(bar, pct);
1762
manual_system_maintenance(true);
1763
render_timer = get_tmr_ms() + render_min_ms;
1764
1765
prevPct = pct;
1766
1767
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
1768
error = -1;
1769
}
1770
1771
if (error)
1772
goto error;
1773
}
1774
lv_bar_set_value(bar, 100);
1775
1776
// Calculate rate for transfer.
1777
u32 rate_1k = (u64)size_bytes_seq * 1000 * 1000 * 1000 / mb_div / timer;
1778
s_printf(txt_buf + strlen(txt_buf), " SEQ 16MB - Rate: #C7EA46 %3d.%02d %s#",
1779
rate_1k / 1000, (rate_1k % 1000) / 10, mbs_text);
1780
lv_label_set_text(lbl_status, txt_buf);
1781
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
1782
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1783
manual_system_maintenance(true);
1784
1785
pct = 0;
1786
prevPct = 200;
1787
timer = 0;
1788
lba_curr = 0;
1789
sector_num = sct_blk_4kb;
1790
data_remaining = sct_rem_4kb;
1791
1792
u32 loop_idx = 0;
1793
render_timer = get_tmr_ms() + render_min_ms;
1794
while (data_remaining)
1795
{
1796
u32 time_taken = get_tmr_us();
1797
error = sdmmc_storage_read(storage, sector_off + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);
1798
time_taken = get_tmr_us() - time_taken;
1799
1800
timer += time_taken;
1801
times_taken_4k[loop_idx++] = time_taken;
1802
1803
manual_system_maintenance(false);
1804
data_remaining -= sector_num;
1805
lba_curr += sector_num;
1806
1807
pct = (lba_curr * 100) / sct_rem_4kb;
1808
if (pct != prevPct && render_timer < get_tmr_ms())
1809
{
1810
lv_bar_set_value(bar, pct);
1811
manual_system_maintenance(true);
1812
render_timer = get_tmr_ms() + render_min_ms;
1813
1814
prevPct = pct;
1815
1816
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
1817
error = -1;
1818
}
1819
1820
if (error)
1821
goto error;
1822
}
1823
lv_bar_set_value(bar, 100);
1824
1825
qsort(times_taken_4k, loop_idx, sizeof(u32), qsort_compare_int); // Use int for faster compare. Value can't exceed 2s.
1826
1827
u32 pct95 = 0;
1828
for (u32 i = 0; i < loop_idx * 95 / 100; i++)
1829
pct95 += times_taken_4k[i];
1830
pct95 /= loop_idx * 95 / 100;
1831
1832
u32 pct05 = 0;
1833
for (u32 i = 0; i < loop_idx * 5 / 100; i++)
1834
pct05 += times_taken_4k[loop_idx - 1 - i];
1835
pct05 /= loop_idx * 5 / 100;
1836
1837
// Calculate rate and IOPS for transfer.
1838
rate_1k = (u64)size_bytes_4kb * 1000 * 1000 * 1000 / mb_div / timer;
1839
u32 iops = ((u64)(sct_rem_4kb / sct_num_1mb) * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
1840
s_printf(txt_buf + strlen(txt_buf), " AVG #C7EA46 95th# #FF3C28 5th#\n");
1841
s_printf(txt_buf + strlen(txt_buf), " SEQ 4KB - Rate: #C7EA46 %3d.%02d %s# IOPS: #C7EA46 %4d# %4d %4d \n",
1842
rate_1k / 1000, (rate_1k % 1000) / 10, mbs_text, iops, 1000000 / pct95, 1000000 / pct05);
1843
lv_label_set_text(lbl_status, txt_buf);
1844
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
1845
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1846
manual_system_maintenance(true);
1847
1848
u32 lba_idx = 0;
1849
u32 random_numbers[4];
1850
for (u32 i = 0; i < rnd_off_cnt; i += 4)
1851
{
1852
// Generate new random numbers.
1853
while (se_rng_pseudo(random_numbers, SE_RNG_BLOCK_SIZE))
1854
;
1855
// Clamp offsets to 256MB range.
1856
random_offsets[i + 0] = random_numbers[0] % sct_rem_4kb;
1857
random_offsets[i + 1] = random_numbers[1] % sct_rem_4kb;
1858
random_offsets[i + 2] = random_numbers[2] % sct_rem_4kb;
1859
random_offsets[i + 3] = random_numbers[3] % sct_rem_4kb;
1860
}
1861
1862
pct = 0;
1863
prevPct = 200;
1864
timer = 0;
1865
data_remaining = sct_rem_4kb;
1866
1867
loop_idx = 0;
1868
render_timer = get_tmr_ms() + render_min_ms;
1869
while (data_remaining)
1870
{
1871
u32 time_taken = get_tmr_us();
1872
error = sdmmc_storage_read(storage, sector_off + random_offsets[lba_idx], sector_num, (u8 *)MIXD_BUF_ALIGNED);
1873
time_taken = get_tmr_us() - time_taken;
1874
1875
timer += time_taken;
1876
times_taken_4k[loop_idx++] = time_taken;
1877
1878
manual_system_maintenance(false);
1879
data_remaining -= sector_num;
1880
lba_idx++;
1881
1882
pct = (lba_idx * 100) / rnd_off_cnt;
1883
if (pct != prevPct && render_timer < get_tmr_ms())
1884
{
1885
lv_bar_set_value(bar, pct);
1886
manual_system_maintenance(true);
1887
render_timer = get_tmr_ms() + render_min_ms;
1888
1889
prevPct = pct;
1890
1891
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
1892
error = -1;
1893
}
1894
1895
if (error)
1896
goto error;
1897
}
1898
lv_bar_set_value(bar, 100);
1899
1900
qsort(times_taken_4k, loop_idx, sizeof(u32), qsort_compare_int); // Use int for faster compare. Value can't exceed 2s.
1901
1902
pct95 = 0;
1903
for (u32 i = 0; i < loop_idx * 95 / 100; i++)
1904
pct95 += times_taken_4k[i];
1905
pct95 /= loop_idx * 95 / 100;
1906
1907
pct05 = 0;
1908
for (u32 i = 0; i < loop_idx * 5 / 100; i++)
1909
pct05 += times_taken_4k[loop_idx - 1 - i];
1910
pct05 /= loop_idx * 5 / 100;
1911
1912
// Calculate rate and IOPS for transfer.
1913
rate_1k = (u64)size_bytes_4kb * 1000 * 1000 * 1000 / mb_div / timer;
1914
iops = ((u64)(sct_rem_4kb / sct_num_1mb) * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
1915
s_printf(txt_buf + strlen(txt_buf), " RND 4KB - Rate: #C7EA46 %3d.%02d %s# IOPS: #C7EA46 %4d# %4d %4d \n",
1916
rate_1k / 1000, (rate_1k % 1000) / 10, mbs_text, iops, 1000000 / pct95, 1000000 / pct05);
1917
if (iter_curr == iters - 1)
1918
txt_buf[strlen(txt_buf) - 1] = 0; // Cut off last new line.
1919
lv_label_set_text(lbl_status, txt_buf);
1920
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
1921
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1922
manual_system_maintenance(true);
1923
}
1924
1925
error:
1926
free(random_offsets);
1927
free(times_taken_4k);
1928
1929
if (error)
1930
{
1931
if (error == -1)
1932
s_printf(txt_buf + strlen(txt_buf), "\n#FFDD00 Aborted! #");
1933
else
1934
s_printf(txt_buf + strlen(txt_buf), "\n#FFDD00 IO Error occurred! #");
1935
1936
lv_label_set_text(lbl_status, txt_buf);
1937
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
1938
}
1939
1940
lv_obj_del(bar);
1941
1942
if (sd_bench && error && error != -1)
1943
sd_end();
1944
if (sd_bench)
1945
{
1946
if (error && error != -1)
1947
sd_end();
1948
else
1949
sd_unmount();
1950
}
1951
else
1952
emmc_end();
1953
1954
out:
1955
s_printf(txt_buf, "#FF8000 %s Benchmark#\n[Raw Reads]", sd_bench ? "SD Card" : "eMMC");
1956
lv_mbox_set_text(mbox, txt_buf);
1957
1958
// Update SDMMC error info in case it changed.
1959
if (sd_bench && bench_sd_err_label)
1960
{
1961
u16 *sd_errors = sd_get_error_count();
1962
s_printf(txt_buf, "\n%d (%d)\n%d (%d)\n%d (%d)",
1963
sd_errors[SD_ERROR_INIT_FAIL], nyx_str->info.sd_errors[SD_ERROR_INIT_FAIL],
1964
sd_errors[SD_ERROR_RW_FAIL], nyx_str->info.sd_errors[SD_ERROR_RW_FAIL],
1965
sd_errors[SD_ERROR_RW_RETRY], nyx_str->info.sd_errors[SD_ERROR_RW_RETRY]);
1966
lv_label_set_text(bench_sd_err_label, txt_buf);
1967
}
1968
1969
free(txt_buf);
1970
1971
lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action); // Important. After set_text.
1972
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1973
1974
return LV_RES_OK;
1975
}
1976
1977
static lv_res_t _create_mbox_emmc_bench(lv_obj_t * btn)
1978
{
1979
_create_mbox_benchmark(false);
1980
1981
return LV_RES_OK;
1982
}
1983
1984
static lv_res_t _create_mbox_sd_bench(lv_obj_t * btn)
1985
{
1986
_create_mbox_benchmark(true);
1987
1988
return LV_RES_OK;
1989
}
1990
1991
static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn)
1992
{
1993
lv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP" Internal eMMC Info", NULL);
1994
lv_win_add_btn(win, NULL, SYMBOL_CHIP" Benchmark", _create_mbox_emmc_bench);
1995
1996
lv_obj_t *desc = lv_cont_create(win, NULL);
1997
lv_obj_set_size(desc, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
1998
1999
lv_obj_t * lb_desc = lv_label_create(desc, NULL);
2000
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
2001
lv_label_set_recolor(lb_desc, true);
2002
2003
char *txt_buf = (char *)malloc(SZ_16K);
2004
txt_buf[0] = '\n';
2005
txt_buf[1] = 0;
2006
u16 *emmc_errors;
2007
2008
if (emmc_initialize(false))
2009
{
2010
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
2011
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
2012
emmc_errors = emmc_get_error_count();
2013
2014
goto out_error;
2015
}
2016
2017
u32 bus_clock = 0;
2018
char *rsvd_blocks;
2019
char life_a_txt[8];
2020
char life_b_txt[8];
2021
char bkops[64];
2022
u32 cache = emmc_storage.ext_csd.cache_size;
2023
u32 life_a = emmc_storage.ext_csd.dev_life_est_a;
2024
u32 life_b = emmc_storage.ext_csd.dev_life_est_b;
2025
u16 card_type = emmc_storage.ext_csd.card_type;
2026
char *max_bus_support = "Unknown";
2027
2028
// Identify manufacturer. Only official eMMCs.
2029
switch (emmc_storage.cid.manfid)
2030
{
2031
case 0x11:
2032
strcat(txt_buf, "Toshiba ");
2033
break;
2034
case 0x15:
2035
strcat(txt_buf, "Samsung ");
2036
break;
2037
case 0x45: // Unofficial.
2038
strcat(txt_buf, "SanDisk ");
2039
lv_win_add_btn(win, NULL, SYMBOL_FILE_ALT" Device Report", _create_mbox_emmc_sandisk_report);
2040
break;
2041
case 0x89: // Unofficial.
2042
strcat(txt_buf, "Silicon Motion ");
2043
break;
2044
case 0x90:
2045
strcat(txt_buf, "SK Hynix ");
2046
break;
2047
default:
2048
strcat(txt_buf, "Unknown ");
2049
break;
2050
}
2051
2052
s_printf(txt_buf + strlen(txt_buf), "(%02X)\n%c%c%c%c%c%c (%02X)\n%d.%d\n%04X\n%02d/%04d\n\n",
2053
emmc_storage.cid.manfid,
2054
emmc_storage.cid.prod_name[0], emmc_storage.cid.prod_name[1], emmc_storage.cid.prod_name[2],
2055
emmc_storage.cid.prod_name[3], emmc_storage.cid.prod_name[4], emmc_storage.cid.prod_name[5],
2056
emmc_storage.cid.oemid,
2057
emmc_storage.cid.prv & 0xF, emmc_storage.cid.prv >> 4,
2058
emmc_storage.cid.serial, emmc_storage.cid.month, emmc_storage.cid.year);
2059
2060
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
2061
max_bus_support = "HS400";
2062
else if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
2063
max_bus_support = "HS200";
2064
else if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
2065
max_bus_support = "DDR52";
2066
else if (card_type & EXT_CSD_CARD_TYPE_HS_52)
2067
max_bus_support = "HS52";
2068
else if (card_type & EXT_CSD_CARD_TYPE_HS_26)
2069
max_bus_support = "HS26";
2070
2071
if (emmc_storage.csd.busspeed == 400)
2072
bus_clock = 200;
2073
else
2074
bus_clock = emmc_storage.csd.busspeed; // Except DDR52 where it's 26 MHz.
2075
2076
strcpy(bkops, "-");
2077
if (emmc_storage.ext_csd.bkops)
2078
{
2079
if (emmc_storage.ext_csd.bkops_en & EXT_CSD_BKOPS_AUTO)
2080
{
2081
strcpy(bkops, "Auto");
2082
if (emmc_storage.ext_csd.bkops_en & EXT_CSD_BKOPS_MANUAL)
2083
strcat(bkops, " + Manual");
2084
}
2085
else
2086
strcpy(bkops, "Off");
2087
strcat(bkops, ": ");
2088
2089
switch (emmc_storage.raw_ext_csd[EXT_CSD_BKOPS_STATUS])
2090
{
2091
case 0:
2092
strcat(bkops, "OK");
2093
break;
2094
case 1:
2095
strcat(bkops, "Minor");
2096
break;
2097
case 2:
2098
strcat(bkops, "#FFDD00 Degraded#");
2099
break;
2100
case 3:
2101
strcat(bkops, "#FFDD00 Critical#");
2102
break;
2103
}
2104
}
2105
2106
strcpy(life_a_txt, "-");
2107
strcpy(life_b_txt, "-");
2108
2109
// Normalize cells life (Used -> Left).
2110
if (life_a) // If 0 no NAND Type A.
2111
{
2112
life_a = (10 - (life_a - 1)) * 10;
2113
s_printf(life_a_txt, "%d%%", life_a);
2114
}
2115
2116
if (life_b) // If 0 no NAND Type B.
2117
{
2118
life_b = (10 - (life_b - 1)) * 10;
2119
s_printf(life_b_txt, "%d%%", life_b);
2120
}
2121
2122
// Reserved blocks used.
2123
switch (emmc_storage.ext_csd.pre_eol_info)
2124
{
2125
case 1:
2126
rsvd_blocks = "Normal (< 80%)";
2127
break;
2128
case 2:
2129
rsvd_blocks = "Warning (> 80%)";
2130
break;
2131
case 3:
2132
rsvd_blocks = "Critical (> 90%)";
2133
break;
2134
default:
2135
rsvd_blocks = "#FF8000 Unknown#";
2136
break;
2137
}
2138
2139
s_printf(txt_buf + strlen(txt_buf),
2140
"#00DDFF V1.%d (rev 1.%d)#\n%02X\n%s\n%d MB/s (%d MHz)\n%d MiB\n%d %s\n\n%s\nA: %s, B: %s\n%s",
2141
emmc_storage.ext_csd.ext_struct, emmc_storage.ext_csd.rev,
2142
emmc_storage.csd.cmdclass, max_bus_support,
2143
emmc_storage.csd.busspeed, bus_clock,
2144
emmc_storage.ext_csd.max_enh_mult * EMMC_BLOCKSIZE / 1024,
2145
!(cache % 1024) ? (cache / 1024) : cache, !(cache % 1024) ? "MiB" : "KiB",
2146
bkops,
2147
life_a_txt, life_b_txt, rsvd_blocks);
2148
2149
lv_label_set_static_text(lb_desc,
2150
"#00DDFF CID:#\n"
2151
"Vendor ID:\n"
2152
"Model:\n"
2153
"Prod Rev:\n"
2154
"S/N:\n"
2155
"Month/Year:\n\n"
2156
"#00DDFF Ext CSD:#\n"
2157
"Cmd Classes:\n"
2158
"Max Bus Rate:\n"
2159
"Current Rate:\n"
2160
"Enhanced Area:\n"
2161
"Write Cache:\n\n"
2162
"Maintenance:\n"
2163
"Estimated Life:\n"
2164
"Reserved Used:"
2165
);
2166
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
2167
2168
lv_obj_t *info = lv_cont_create(win, NULL);
2169
lv_obj_set_size(info, LV_HOR_RES / 11 * 3, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
2170
2171
lv_obj_t * lb_val = lv_label_create(info, lb_desc);
2172
2173
lv_label_set_text(lb_val, txt_buf);
2174
2175
lv_obj_set_width(lb_val, lv_obj_get_width(info));
2176
lv_obj_align(info, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2177
2178
lv_obj_t *desc2 = lv_cont_create(win, NULL);
2179
lv_obj_set_size(desc2, LV_HOR_RES / 2 / 4 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
2180
2181
lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);
2182
lv_label_set_style(lb_desc2, &monospace_text);
2183
2184
u32 boot_size = emmc_storage.ext_csd.boot_mult << 17;
2185
u32 rpmb_size = emmc_storage.ext_csd.rpmb_mult << 17;
2186
strcpy(txt_buf, "#00DDFF eMMC Physical Partitions:#\n");
2187
s_printf(txt_buf + strlen(txt_buf), "1: #96FF00 BOOT0# Size: %6d KiB Sectors: 0x%08X\n", boot_size / 1024, boot_size / EMMC_BLOCKSIZE);
2188
s_printf(txt_buf + strlen(txt_buf), "2: #96FF00 BOOT1# Size: %6d KiB Sectors: 0x%08X\n", boot_size / 1024, boot_size / EMMC_BLOCKSIZE);
2189
s_printf(txt_buf + strlen(txt_buf), "3: #96FF00 RPMB# Size: %6d KiB Sectors: 0x%08X\n", rpmb_size / 1024, rpmb_size / EMMC_BLOCKSIZE);
2190
s_printf(txt_buf + strlen(txt_buf), "0: #96FF00 GPP# Size: %6d MiB Sectors: 0x%08X\n", emmc_storage.sec_cnt >> SECTORS_TO_MIB_COEFF, emmc_storage.sec_cnt);
2191
strcat(txt_buf, "\n#00DDFF GPP (eMMC USER) Partition Table:#\n");
2192
2193
emmc_set_partition(EMMC_GPP);
2194
LIST_INIT(gpt);
2195
emmc_gpt_parse(&gpt);
2196
2197
u32 idx = 0;
2198
int lines_left = 20;
2199
s_printf(txt_buf + strlen(txt_buf), "#FFBA00 Idx Name Size Offset Sectors#\n");
2200
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
2201
{
2202
int lines = strlen(part->name) > 25 ? 2 : 1;
2203
if ((lines_left - lines) <= 0)
2204
{
2205
strcat(txt_buf, "#FFDD00 Table does not fit on screen...#");
2206
break;
2207
}
2208
2209
if (lines == 2)
2210
{
2211
s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %s#\n %6d MiB %8Xh %8Xh\n",
2212
part->index, part->name, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
2213
part->lba_start, part->lba_end - part->lba_start + 1);
2214
}
2215
else
2216
{
2217
s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %.25s# %6d MiB %8Xh %8Xh\n",
2218
part->index, part->name, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
2219
part->lba_start, part->lba_end - part->lba_start + 1);
2220
}
2221
2222
lines_left -= lines;
2223
idx++;
2224
}
2225
if (!idx)
2226
strcat(txt_buf, "#FFDD00 Partition table is empty!#");
2227
2228
emmc_gpt_free(&gpt);
2229
2230
lv_label_set_text(lb_desc2, txt_buf);
2231
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
2232
lv_obj_align(desc2, info, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 6, 0);
2233
2234
emmc_errors = emmc_get_error_count();
2235
if (emmc_get_mode() < EMMC_MMC_HS400 ||
2236
emmc_errors[EMMC_ERROR_INIT_FAIL] ||
2237
emmc_errors[EMMC_ERROR_RW_FAIL] ||
2238
emmc_errors[EMMC_ERROR_RW_RETRY])
2239
{
2240
out_error:
2241
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
2242
lv_obj_set_style(dark_bg, &mbox_darken);
2243
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
2244
2245
static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
2246
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
2247
lv_mbox_set_recolor_text(mbox, true);
2248
2249
s_printf(txt_buf,
2250
"#FF8000 eMMC Issues Warning#\n\n"
2251
"#FFDD00 Your eMMC is initialized in a slower mode,#\n"
2252
"#FFDD00 or init/read/write errors occurred!#\n"
2253
"#FFDD00 This might mean hardware issues!#\n\n"
2254
"#00DDFF Bus Speed:# %d MB/s\n\n"
2255
"#00DDFF SDMMC4 Errors:#\n"
2256
"Init fails: %d\n"
2257
"Read/Write fails: %d\n"
2258
"Read/Write errors: %d",
2259
emmc_storage.csd.busspeed,
2260
emmc_errors[EMMC_ERROR_INIT_FAIL],
2261
emmc_errors[EMMC_ERROR_RW_FAIL],
2262
emmc_errors[EMMC_ERROR_RW_RETRY]);
2263
2264
lv_mbox_set_text(mbox, txt_buf);
2265
lv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);
2266
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);
2267
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
2268
lv_obj_set_top(mbox, true);
2269
}
2270
2271
emmc_end();
2272
free(txt_buf);
2273
2274
return LV_RES_OK;
2275
}
2276
2277
static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
2278
{
2279
lv_obj_t *win = nyx_create_standard_window(SYMBOL_SD" microSD Card Info", NULL);
2280
lv_win_add_btn(win, NULL, SYMBOL_SD" Benchmark", _create_mbox_sd_bench);
2281
2282
lv_obj_t *desc = lv_cont_create(win, NULL);
2283
lv_obj_set_size(desc, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
2284
2285
lv_obj_t * lb_desc = lv_label_create(desc, NULL);
2286
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
2287
lv_label_set_recolor(lb_desc, true);
2288
2289
lv_label_set_text(lb_desc, "#D4FF00 Please wait...#");
2290
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
2291
2292
// Disable buttons.
2293
nyx_window_toggle_buttons(win, true);
2294
2295
manual_system_maintenance(true);
2296
2297
if (sd_mount())
2298
{
2299
lv_label_set_text(lb_desc, "#FFDD00 Failed to init SD!#");
2300
goto failed;
2301
}
2302
2303
lv_label_set_text(lb_desc,
2304
"#00DDFF Card ID:#\n"
2305
"Vendor ID:\n"
2306
"Model:\n"
2307
"OEM ID:\n"
2308
"HW rev:\n"
2309
"FW rev:\n"
2310
"S/N:\n"
2311
"Month/Year:\n\n"
2312
"Max Power:\n"
2313
"Initial bus:"
2314
);
2315
2316
lv_obj_t *val = lv_cont_create(win, NULL);
2317
lv_obj_set_size(val, LV_HOR_RES / 12 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
2318
2319
lv_obj_t * lb_val = lv_label_create(val, lb_desc);
2320
2321
char *txt_buf = (char *)malloc(SZ_16K);
2322
txt_buf[0] = '\n';
2323
txt_buf[1] = 0;
2324
2325
// Identify manufacturer.
2326
switch (sd_storage.cid.manfid)
2327
{
2328
case 0x00:
2329
strcat(txt_buf, "#FFDD00 Fake# ");
2330
break;
2331
case 0x01:
2332
strcat(txt_buf, "Panasonic ");
2333
break;
2334
case 0x02:
2335
strcat(txt_buf, "Toshiba ");
2336
break;
2337
case 0x03:
2338
if (!memcmp(&sd_storage.cid.oemid, "DW", 2))
2339
strcat(txt_buf, "Western Digital "); // WD.
2340
else
2341
strcat(txt_buf, "SanDisk ");
2342
break;
2343
case 0x06:
2344
strcat(txt_buf, "Ritek ");
2345
break;
2346
case 0x09:
2347
strcat(txt_buf, "ATP ");
2348
break;
2349
case 0x13:
2350
strcat(txt_buf, "Kingmax ");
2351
break;
2352
case 0x19:
2353
strcat(txt_buf, "Dynacard ");
2354
break;
2355
case 0x1A:
2356
strcat(txt_buf, "Power Quotient ");
2357
break;
2358
case 0x1B:
2359
strcat(txt_buf, "Samsung ");
2360
break;
2361
case 0x1D:
2362
strcat(txt_buf, "AData ");
2363
break;
2364
case 0x27:
2365
strcat(txt_buf, "Phison ");
2366
break;
2367
case 0x28:
2368
strcat(txt_buf, "Barun Electronics ");
2369
break;
2370
case 0x31:
2371
strcat(txt_buf, "Silicon Power ");
2372
break;
2373
case 0x41:
2374
strcat(txt_buf, "Kingston ");
2375
break;
2376
case 0x51:
2377
strcat(txt_buf, "STEC ");
2378
break;
2379
case 0x5D:
2380
strcat(txt_buf, "SwissBit ");
2381
break;
2382
case 0x61:
2383
strcat(txt_buf, "Netlist ");
2384
break;
2385
case 0x63:
2386
strcat(txt_buf, "Cactus ");
2387
break;
2388
case 0x73:
2389
strcat(txt_buf, "Bongiovi ");
2390
break;
2391
case 0x74:
2392
strcat(txt_buf, "Jiaelec ");
2393
break;
2394
case 0x76:
2395
strcat(txt_buf, "Patriot ");
2396
break;
2397
case 0x82:
2398
strcat(txt_buf, "Jiang Tay ");
2399
break;
2400
case 0x83:
2401
strcat(txt_buf, "Netcom ");
2402
break;
2403
case 0x84:
2404
strcat(txt_buf, "Strontium ");
2405
break;
2406
case 0x9C:
2407
if (!memcmp(&sd_storage.cid.oemid, "OS", 2))
2408
strcat(txt_buf, "Sony "); // SO.
2409
else
2410
strcat(txt_buf, "Barun Electronics "); // BE.
2411
break;
2412
case 0x9F:
2413
strcat(txt_buf, "Taishin ");
2414
break;
2415
case 0xAD:
2416
strcat(txt_buf, "Longsys ");
2417
break;
2418
default:
2419
strcat(txt_buf, "Unknown ");
2420
break;
2421
}
2422
2423
// UHS-I max power limit is 400mA, no matter what the card says.
2424
u32 max_power_nominal = sd_storage.max_power > 400 ? 400 : sd_storage.max_power;
2425
2426
s_printf(txt_buf + strlen(txt_buf), "(%02X)\n%c%c%c%c%c\n%c%c (%04X)\n%X\n%X\n%08x\n%02d/%04d\n\n%d mW (%d mA)\n",
2427
sd_storage.cid.manfid,
2428
sd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2],
2429
sd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4],
2430
(sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF, sd_storage.cid.oemid,
2431
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
2432
sd_storage.cid.month, sd_storage.cid.year,
2433
max_power_nominal * 3600 / 1000, sd_storage.max_power);
2434
2435
switch (nyx_str->info.sd_init)
2436
{
2437
case SD_1BIT_HS25:
2438
strcat(txt_buf, "HS25 1bit");
2439
break;
2440
case SD_4BIT_HS25:
2441
strcat(txt_buf, "HS25");
2442
break;
2443
case SD_UHS_SDR82: // Report as SDR104.
2444
case SD_UHS_SDR104:
2445
strcat(txt_buf, "SDR104");
2446
break;
2447
case 0:
2448
default:
2449
strcat(txt_buf, "Undefined");
2450
break;
2451
}
2452
2453
lv_label_set_text(lb_val, txt_buf);
2454
2455
lv_obj_set_width(lb_val, lv_obj_get_width(val));
2456
lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2457
2458
lv_obj_t *desc2 = lv_cont_create(win, NULL);
2459
lv_obj_set_size(desc2, LV_HOR_RES / 2 / 11 * 5, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
2460
2461
lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);
2462
2463
lv_label_set_static_text(lb_desc2,
2464
"#00DDFF Card-Specific Data#\n"
2465
"Cmd Classes:\n"
2466
"Capacity:\n"
2467
"Capacity (LBA):\n"
2468
"Bus Width:\n"
2469
"Current Rate:\n"
2470
"Speed Class:\n"
2471
"UHS Classes:\n"
2472
"Max Bus Speed:\n\n"
2473
"Write Protect:"
2474
);
2475
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
2476
lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 5 * 3, 0);
2477
2478
lv_obj_t *val2 = lv_cont_create(win, NULL);
2479
lv_obj_set_size(val2, LV_HOR_RES / 4, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
2480
2481
lv_obj_t * lb_val2 = lv_label_create(val2, lb_desc);
2482
2483
char *wp_info;
2484
switch (sd_storage.csd.write_protect)
2485
{
2486
case 1:
2487
wp_info = "Temporary";
2488
break;
2489
case 2:
2490
case 3:
2491
wp_info = "Permanent";
2492
break;
2493
default:
2494
wp_info = "None";
2495
break;
2496
}
2497
2498
bool uhs_au_mb = false;
2499
u32 uhs_au_size = sd_storage_get_ssr_au(&sd_storage);
2500
if (uhs_au_size >= 1024)
2501
{
2502
uhs_au_mb = true;
2503
uhs_au_size /= 1024;
2504
}
2505
2506
sd_func_modes_t fmodes = { 0 };
2507
sd_storage_get_fmodes(&sd_storage, NULL, &fmodes);
2508
2509
char *bus_speed;
2510
if (fmodes.cmd_system & SD_MODE_UHS_DDR200)
2511
bus_speed = "DDR200";
2512
else if (fmodes.access_mode & SD_MODE_UHS_SDR104)
2513
bus_speed = "SDR104";
2514
else if (fmodes.access_mode & SD_MODE_UHS_SDR50)
2515
bus_speed = "SDR50";
2516
else if (fmodes.access_mode & SD_MODE_UHS_DDR50)
2517
bus_speed = "DDR50";
2518
else if (fmodes.access_mode & SD_MODE_UHS_SDR25)
2519
bus_speed = "SDR25";
2520
else
2521
bus_speed = "SDR12";
2522
2523
char *cpe = NULL;
2524
if (sd_storage.ssr.app_class == 2)
2525
{
2526
u8 *buf = zalloc(512);
2527
2528
// Directly get and parse ext reg for performance enhance.
2529
sd_storage_parse_perf_enhance(&sd_storage, 2, 0, 0, buf);
2530
2531
bool has_perf_enhance = sd_storage.ser.cache &&
2532
sd_storage.ser.cmdq &&
2533
sd_storage.ser.cache == sd_storage.ser.cache_ext &&
2534
sd_storage.ser.cmdq == sd_storage.ser.cmdq_ext;
2535
if (has_perf_enhance)
2536
cpe = "#FFDD00 "; // CMDQ/CACHE support via a quirk.
2537
else
2538
cpe = "#FF3C28 "; // Broken.
2539
2540
// Get and parse ext reg for performance enhance in spec.
2541
sd_storage_get_ext_regs(&sd_storage, buf);
2542
2543
if (sd_storage.ser.valid)
2544
{
2545
has_perf_enhance = sd_storage.ser.cache &&
2546
sd_storage.ser.cmdq &&
2547
sd_storage.ser.cache == sd_storage.ser.cache_ext &&
2548
sd_storage.ser.cmdq == sd_storage.ser.cmdq_ext;
2549
2550
if (has_perf_enhance)
2551
cpe = NULL; // CMDQ/CACHE support in spec.
2552
else
2553
cpe = "#FF3C28 "; // Broken.
2554
}
2555
2556
free(buf);
2557
}
2558
2559
s_printf(txt_buf,
2560
"#00DDFF v%d.0#\n"
2561
"%02X\n"
2562
"%d MiB\n"
2563
"%X (CP %X)\n"
2564
"%d\n"
2565
"%d MB/s (%d MHz)\n"
2566
"%d (AU: %d %s\n"
2567
"U%d V%d %sA%d%s\n"
2568
"%s\n\n"
2569
"%s",
2570
sd_storage.csd.structure + 1,
2571
sd_storage.csd.cmdclass,
2572
sd_storage.sec_cnt >> 11,
2573
sd_storage.sec_cnt, sd_storage.ssr.protected_size >> 9,
2574
sd_storage.ssr.bus_width,
2575
sd_storage.csd.busspeed,
2576
(sd_storage.csd.busspeed > 10) ? (sd_storage.csd.busspeed * 2) : 50,
2577
sd_storage.ssr.speed_class, uhs_au_size, uhs_au_mb ? "MiB)" : "KiB)",
2578
sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class, cpe ? cpe : "", sd_storage.ssr.app_class, cpe ? "#" : "",
2579
bus_speed,
2580
wp_info);
2581
2582
lv_label_set_text(lb_val2, txt_buf);
2583
2584
lv_obj_set_width(lb_val2, lv_obj_get_width(val2));
2585
lv_obj_align(val2, desc2, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2586
2587
lv_obj_t *line_sep = lv_line_create(win, NULL);
2588
static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 12, 0} };
2589
lv_line_set_points(line_sep, line_pp, 2);
2590
lv_line_set_style(line_sep, lv_theme_get_current()->line.decor);
2591
lv_obj_align(line_sep, desc, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 410 / 100, LV_DPI / 7);
2592
2593
lv_obj_t *desc3 = lv_cont_create(win, NULL);
2594
lv_obj_set_size(desc3, LV_HOR_RES / 2 / 2 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
2595
2596
lv_obj_t * lb_desc3 = lv_label_create(desc3, lb_desc);
2597
lv_label_set_text(lb_desc3, "#D4FF00 Acquiring info...#");
2598
lv_obj_set_width(lb_desc3, lv_obj_get_width(desc3));
2599
2600
lv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
2601
2602
manual_system_maintenance(true);
2603
2604
lv_obj_set_size(desc3, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
2605
lv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
2606
2607
lv_obj_t *val3 = lv_cont_create(win, NULL);
2608
lv_obj_set_size(val3, LV_HOR_RES / 12 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
2609
2610
lv_obj_t * lb_val3 = lv_label_create(val3, lb_desc);
2611
lv_label_set_text(lb_val3, "");
2612
2613
lv_obj_align(val3, desc3, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2614
2615
lv_obj_t *desc4 = lv_cont_create(win, NULL);
2616
lv_obj_set_size(desc4, LV_HOR_RES / 2 / 2 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
2617
2618
lv_obj_t * lb_desc4 = lv_label_create(desc4, lb_desc);
2619
lv_label_set_text(lb_desc4, " ");
2620
lv_obj_set_width(lb_desc4, lv_obj_get_width(desc4));
2621
2622
lv_label_set_text(lb_desc4,
2623
"#00DDFF SDMMC1 Errors:#\n"
2624
"Init fails:\n"
2625
"Read/Write fails:\n"
2626
"Read/Write errors:"
2627
);
2628
lv_obj_set_size(desc4, LV_HOR_RES / 2 / 11 * 5, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
2629
lv_obj_set_width(lb_desc4, lv_obj_get_width(desc4));
2630
lv_obj_align(desc4, val3, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 5 * 3, 0);
2631
2632
lv_obj_t *val4 = lv_cont_create(win, NULL);
2633
lv_obj_set_size(val4, LV_HOR_RES / 4, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
2634
2635
lv_obj_t *lb_val4 = lv_label_create(val4, lb_desc);
2636
bench_sd_err_label = lb_val4;
2637
2638
u16 *sd_errors = sd_get_error_count();
2639
s_printf(txt_buf, "\n%d (%d)\n%d (%d)\n%d (%d)",
2640
sd_errors[SD_ERROR_INIT_FAIL], nyx_str->info.sd_errors[SD_ERROR_INIT_FAIL],
2641
sd_errors[SD_ERROR_RW_FAIL], nyx_str->info.sd_errors[SD_ERROR_RW_FAIL],
2642
sd_errors[SD_ERROR_RW_RETRY], nyx_str->info.sd_errors[SD_ERROR_RW_RETRY]);
2643
2644
lv_label_set_text(lb_val4, txt_buf);
2645
2646
lv_obj_set_width(lb_val4, lv_obj_get_width(val4));
2647
lv_obj_align(val4, desc4, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2648
2649
manual_system_maintenance(true);
2650
2651
f_getfree("", &sd_fs.free_clst, NULL);
2652
2653
lv_label_set_text(lb_desc3,
2654
"#00DDFF Found FAT FS:#\n"
2655
"Filesystem:\n"
2656
"Cluster:\n"
2657
"Size free/total:"
2658
);
2659
2660
lv_obj_set_width(lb_desc3, lv_obj_get_width(desc3));
2661
2662
s_printf(txt_buf, "\n%s\n%d %s\n%d/%d MiB",
2663
sd_fs.fs_type == FS_EXFAT ? ("exFAT "SYMBOL_SHRK) : ("FAT32"),
2664
(sd_fs.csize > 1) ? (sd_fs.csize >> 1) : SD_BLOCKSIZE,
2665
(sd_fs.csize > 1) ? "KiB" : "B",
2666
(u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF),
2667
(u32)(sd_fs.n_fatent * sd_fs.csize >> SECTORS_TO_MIB_COEFF));
2668
2669
lv_label_set_text(lb_val3, txt_buf);
2670
2671
lv_obj_set_width(lb_val3, lv_obj_get_width(val3));
2672
2673
free(txt_buf);
2674
sd_unmount();
2675
2676
failed:
2677
nyx_window_toggle_buttons(win, false);
2678
2679
return LV_RES_OK;
2680
}
2681
2682
static lv_res_t _create_window_battery_status(lv_obj_t *btn)
2683
{
2684
lv_obj_t *win = nyx_create_standard_window(SYMBOL_BATTERY_FULL" Battery Info", NULL);
2685
lv_win_add_btn(win, NULL, SYMBOL_DOWNLOAD" Dump Fuel Regs", _battery_dump_window_action);
2686
2687
lv_obj_t *desc = lv_cont_create(win, NULL);
2688
lv_obj_set_size(desc, LV_HOR_RES / 2 / 4 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
2689
2690
lv_obj_t * lb_desc = lv_label_create(desc, NULL);
2691
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
2692
lv_label_set_recolor(lb_desc, true);
2693
2694
lv_label_set_static_text(lb_desc,
2695
"#00DDFF Fuel Gauge IC Info:#\n"
2696
"Capacity now:\n"
2697
"Capacity full:\n"
2698
"Capacity (design):\n"
2699
"Current now:\n"
2700
"Current average:\n"
2701
"Voltage now:\n"
2702
"Voltage open-circuit:\n"
2703
"Min voltage reached:\n"
2704
"Max voltage reached:\n"
2705
"Empty voltage:\n"
2706
"Battery temp:\n\n"
2707
"#00DDFF PMIC IC Info:#\n"
2708
"Main PMIC:\n\n"
2709
"CPU/GPU PMIC:\n"
2710
);
2711
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
2712
2713
lv_obj_t *val = lv_cont_create(win, NULL);
2714
lv_obj_set_size(val, LV_HOR_RES / 5, LV_VER_RES - (LV_DPI * 11 / 7));
2715
2716
lv_obj_t * lb_val = lv_label_create(val, lb_desc);
2717
2718
char *txt_buf = (char *)malloc(SZ_16K);
2719
int value = 0;
2720
2721
// Fuel gauge IC info.
2722
if (!max17050_get_version(NULL))
2723
{
2724
int cap_pct = 0;
2725
max17050_get_property(MAX17050_RepSOC, &cap_pct);
2726
max17050_get_property(MAX17050_RepCap, &value);
2727
s_printf(txt_buf, "\n%d mAh [%d %%]\n", value, cap_pct >> 8);
2728
2729
max17050_get_property(MAX17050_FullCAP, &value);
2730
s_printf(txt_buf + strlen(txt_buf), "%d mAh\n", value);
2731
2732
max17050_get_property(MAX17050_DesignCap, &value);
2733
bool design_cap_init = value == 1000;
2734
s_printf(txt_buf + strlen(txt_buf), "%s%d mAh%s\n",
2735
design_cap_init ? "#FF8000 " : "", value, design_cap_init ? " - Init "SYMBOL_WARNING"#" : "");
2736
2737
max17050_get_property(MAX17050_Current, &value);
2738
s_printf(txt_buf + strlen(txt_buf), "%d mA\n", value / 1000);
2739
2740
max17050_get_property(MAX17050_AvgCurrent, &value);
2741
s_printf(txt_buf + strlen(txt_buf), "%d mA\n", value / 1000);
2742
2743
max17050_get_property(MAX17050_VCELL, &value);
2744
bool voltage_empty = value < 3200;
2745
s_printf(txt_buf + strlen(txt_buf), "%s%d mV%s\n",
2746
voltage_empty ? "#FF8000 " : "", value, voltage_empty ? " - Low "SYMBOL_WARNING"#" : "");
2747
2748
max17050_get_property(MAX17050_OCVInternal, &value);
2749
s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value);
2750
2751
max17050_get_property(MAX17050_MinVolt, &value);
2752
s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value);
2753
2754
max17050_get_property(MAX17050_MaxVolt, &value);
2755
s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value);
2756
2757
max17050_get_property(MAX17050_V_empty, &value);
2758
s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value);
2759
2760
max17050_get_property(MAX17050_TEMP, &value);
2761
s_printf(txt_buf + strlen(txt_buf), "%d.%d oC\n\n\n", value / 10, (value >= 0 ? value : (~value + 1)) % 10);
2762
}
2763
else
2764
strcpy(txt_buf, "\n#FF8000 "SYMBOL_WARNING" Error!#\n\n\n\n\n\n\n\n\n\n\n\n\n");
2765
2766
// Main Pmic IC info.
2767
value = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4);
2768
u32 main_pmic_version = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID3) & 0xF;
2769
2770
if (value == 0x35)
2771
s_printf(txt_buf + strlen(txt_buf), "max77620 v%d\nErista OTP\n", main_pmic_version);
2772
else if (value == 0x53)
2773
s_printf(txt_buf + strlen(txt_buf), "max77620 v%d\nMariko OTP\n", main_pmic_version);
2774
else
2775
s_printf(txt_buf + strlen(txt_buf), "max77620 v%d\n#FF8000 Unknown OTP# (%02X)\n", main_pmic_version, value);
2776
2777
// CPU/GPU/DRAM Pmic IC info.
2778
u32 cpu_gpu_pmic_type = h_cfg.t210b01 ? (FUSE(FUSE_RESERVED_ODM28_B01) & 1) + 1 : 0;
2779
switch (cpu_gpu_pmic_type)
2780
{
2781
case 0:
2782
s_printf(txt_buf + strlen(txt_buf), "max77621 v%d",
2783
i2c_recv_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_REG_CHIPID1));
2784
break;
2785
case 1:
2786
s_printf(txt_buf + strlen(txt_buf), "max77812-2 v%d", // High power GPU. 2 Outputs, phases 3 1.
2787
i2c_recv_byte(I2C_5, MAX77812_PHASE31_CPU_I2C_ADDR, MAX77812_REG_VERSION) & 7);
2788
break;
2789
case 2:
2790
s_printf(txt_buf + strlen(txt_buf), "max77812-3 v%d.0", // Low power GPU. 3 Outputs, phases 2 1 1.
2791
i2c_recv_byte(I2C_5, MAX77812_PHASE211_CPU_I2C_ADDR, MAX77812_REG_VERSION) & 7);
2792
break;
2793
}
2794
2795
lv_label_set_text(lb_val, txt_buf);
2796
2797
lv_obj_set_width(lb_val, lv_obj_get_width(val));
2798
lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2799
2800
lv_obj_t *desc2 = lv_cont_create(win, NULL);
2801
lv_obj_set_size(desc2, LV_HOR_RES / 2 / 7 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
2802
2803
lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);
2804
2805
lv_label_set_static_text(lb_desc2,
2806
"#00DDFF Battery Charger IC Info:#\n"
2807
"Input current limit:\n"
2808
"System voltage limit:\n"
2809
"Charge current limit:\n"
2810
"Charge voltage limit:\n"
2811
"Charge status:\n"
2812
"Temperature status:\n\n"
2813
"#00DDFF USB-PD IC Info:#\n"
2814
"Connection status:\n"
2815
"Input Wattage Limit:\n"
2816
"USB-PD Profiles:"
2817
);
2818
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
2819
lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0);
2820
2821
lv_obj_t *val2 = lv_cont_create(win, NULL);
2822
lv_obj_set_size(val2, LV_HOR_RES / 2 / 3, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
2823
2824
lv_obj_t * lb_val2 = lv_label_create(val2, lb_desc);
2825
int iinlim = 0;
2826
2827
// Charger IC info.
2828
if (!bq24193_get_version(NULL))
2829
{
2830
bq24193_get_property(BQ24193_InputCurrentLimit, &iinlim);
2831
s_printf(txt_buf, "\n%d mA\n", iinlim);
2832
2833
bq24193_get_property(BQ24193_SystemMinimumVoltage, &value);
2834
s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value);
2835
2836
bq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);
2837
s_printf(txt_buf + strlen(txt_buf), "%d mA\n", value);
2838
2839
bq24193_get_property(BQ24193_ChargeVoltageLimit, &value);
2840
s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value);
2841
2842
bq24193_get_property(BQ24193_ChargeStatus, &value);
2843
switch (value)
2844
{
2845
case 0:
2846
strcat(txt_buf, "Not charging\n");
2847
break;
2848
case 1:
2849
strcat(txt_buf, "Pre-charging\n");
2850
break;
2851
case 2:
2852
strcat(txt_buf, "Fast charging\n");
2853
break;
2854
case 3:
2855
strcat(txt_buf, "Charge terminated\n");
2856
break;
2857
default:
2858
s_printf(txt_buf + strlen(txt_buf), "Unknown (%d)\n", value);
2859
break;
2860
}
2861
2862
bq24193_get_property(BQ24193_TempStatus, &value);
2863
switch (value)
2864
{
2865
case 0:
2866
strcat(txt_buf, "Normal");
2867
break;
2868
case 2:
2869
strcat(txt_buf, "Warm");
2870
break;
2871
case 3:
2872
strcat(txt_buf, "Cool");
2873
break;
2874
case 5:
2875
strcat(txt_buf, "#FF8000 Cold#");
2876
break;
2877
case 6:
2878
strcat(txt_buf, "#FF8000 Hot#");
2879
break;
2880
default:
2881
s_printf(txt_buf + strlen(txt_buf), "Unknown (%d)", value);
2882
break;
2883
}
2884
}
2885
else
2886
strcpy(txt_buf, "\n#FF8000 "SYMBOL_WARNING" Error!#\n\n\n\n\n");
2887
2888
strcat(txt_buf, "\n\n\n");
2889
2890
// USB-PD IC info.
2891
if (!bm92t36_get_version(NULL))
2892
{
2893
bool inserted;
2894
u32 wattage = 0;
2895
usb_pd_objects_t usb_pd;
2896
bm92t36_get_source_info(&inserted, &usb_pd);
2897
strcat(txt_buf, inserted ? "Connected" : "Disconnected");
2898
2899
// Select 5V is no PD contract.
2900
wattage = iinlim * (usb_pd.pdo_no ? usb_pd.selected_pdo.voltage : 5);
2901
2902
s_printf(txt_buf + strlen(txt_buf), "\n%d.%d W", wattage / 1000, (wattage % 1000) / 100);
2903
2904
if (!usb_pd.pdo_no)
2905
strcat(txt_buf, "\nNon PD");
2906
2907
// Show 6 profiles max so they can fit.
2908
usb_pd.pdo_no = MIN(usb_pd.pdo_no, 6);
2909
for (u32 i = 0; i < usb_pd.pdo_no; i++)
2910
{
2911
bool selected =
2912
usb_pd.pdos[i].amperage == usb_pd.selected_pdo.amperage &&
2913
usb_pd.pdos[i].voltage == usb_pd.selected_pdo.voltage;
2914
s_printf(txt_buf + strlen(txt_buf), "\n%s%d mA, %2d V%s",
2915
selected ? "#D4FF00 " : "",
2916
usb_pd.pdos[i].amperage, usb_pd.pdos[i].voltage,
2917
selected ? "#" : "");
2918
}
2919
}
2920
else
2921
strcat(txt_buf, "#FF8000 "SYMBOL_WARNING" Error!#");
2922
2923
lv_label_set_text(lb_val2, txt_buf);
2924
2925
lv_obj_set_width(lb_val2, lv_obj_get_width(val2));
2926
lv_obj_align(val2, desc2, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2927
2928
free(txt_buf);
2929
2930
return LV_RES_OK;
2931
}
2932
2933
static bool _lockpick_exists_check()
2934
{
2935
#define LOCKPICK_MAGIC_OFFSET 0x118
2936
#define LOCKPICK_VERSION_OFFSET 0x11C
2937
#define LOCKPICK_MAGIC 0x4B434F4C // LOCK.
2938
#define LOCKPICK_MIN_VERSION 0x1090500 // 1.9.5.
2939
2940
bool found = false;
2941
void *buf = malloc(0x200);
2942
if (!sd_mount())
2943
{
2944
FIL fp;
2945
if (f_open(&fp, "bootloader/payloads/Lockpick_RCM.bin", FA_READ))
2946
goto out;
2947
2948
// Read Lockpick payload and check versioning.
2949
if (f_read(&fp, buf, 0x200, NULL))
2950
{
2951
f_close(&fp);
2952
2953
goto out;
2954
}
2955
2956
u32 magic = *(u32 *)(buf + LOCKPICK_MAGIC_OFFSET);
2957
u32 version = byte_swap_32(*(u32 *)(buf + LOCKPICK_VERSION_OFFSET) - 0x303030);
2958
2959
if (magic == LOCKPICK_MAGIC && version >= LOCKPICK_MIN_VERSION)
2960
found = true;
2961
2962
f_close(&fp);
2963
}
2964
2965
out:
2966
free(buf);
2967
sd_unmount();
2968
2969
return found;
2970
}
2971
2972
void create_tab_info(lv_theme_t *th, lv_obj_t *parent)
2973
{
2974
lv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY);
2975
2976
static lv_style_t h_style;
2977
lv_style_copy(&h_style, &lv_style_transp);
2978
h_style.body.padding.inner = 0;
2979
h_style.body.padding.hor = LV_DPI - (LV_DPI / 4);
2980
h_style.body.padding.ver = LV_DPI / 6;
2981
2982
// Create SoC Info container.
2983
lv_obj_t *h1 = lv_cont_create(parent, NULL);
2984
lv_cont_set_style(h1, &h_style);
2985
lv_cont_set_fit(h1, false, true);
2986
lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);
2987
lv_obj_set_click(h1, false);
2988
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
2989
2990
lv_obj_t *label_sep = lv_label_create(h1, NULL);
2991
lv_label_set_static_text(label_sep, "");
2992
2993
lv_obj_t *label_txt = lv_label_create(h1, NULL);
2994
lv_label_set_static_text(label_txt, "SoC & HW Info");
2995
lv_obj_set_style(label_txt, th->label.prim);
2996
lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, 0);
2997
2998
lv_obj_t *line_sep = lv_line_create(h1, NULL);
2999
static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };
3000
lv_line_set_points(line_sep, line_pp, 2);
3001
lv_line_set_style(line_sep, th->line.decor);
3002
lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
3003
3004
// Create Bootrom button.
3005
lv_obj_t *btn = lv_btn_create(h1, NULL);
3006
if (hekate_bg)
3007
{
3008
lv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_transp_rel);
3009
lv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_transp_pr);
3010
lv_btn_set_style(btn, LV_BTN_STYLE_INA, &btn_transp_ina);
3011
}
3012
lv_obj_t *label_btn = lv_label_create(btn, NULL);
3013
lv_btn_set_fit(btn, true, true);
3014
lv_label_set_static_text(label_btn, SYMBOL_CHIP" Bootrom");
3015
lv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
3016
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _create_window_bootrom_info_status);
3017
3018
// Create TSEC Keys button.
3019
lv_obj_t *btn2 = lv_btn_create(h1, btn);
3020
label_btn = lv_label_create(btn2, NULL);
3021
lv_label_set_static_text(label_btn, SYMBOL_KEY" Lockpick");
3022
lv_obj_align(btn2, btn, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 11 / 15, 0);
3023
lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_mbox_lockpick);
3024
3025
bool lockpick_found = _lockpick_exists_check();
3026
if (!lockpick_found)
3027
lv_btn_set_state(btn2, LV_BTN_STATE_INA);
3028
3029
lv_obj_t *label_txt2 = lv_label_create(h1, NULL);
3030
lv_label_set_recolor(label_txt2, true);
3031
3032
if (lockpick_found)
3033
{
3034
lv_label_set_static_text(label_txt2,
3035
"View Ipatches and dump the unpatched and patched versions\nof BootROM.\n"
3036
"Or dump every single key via #C7EA46 Lockpick RCM#.\n");
3037
}
3038
else
3039
{
3040
lv_label_set_static_text(label_txt2,
3041
"View Ipatches and dump the unpatched and patched versions\nof BootROM. Or dump every single key via #C7EA46 Lockpick RCM#.\n"
3042
"#FFDD00 bootloader/payloads/Lockpick_RCM.bin is missing or old!#\n");
3043
}
3044
3045
lv_obj_set_style(label_txt2, &hint_small_style);
3046
lv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
3047
3048
static lv_style_t line_style;
3049
lv_style_copy(&line_style, th->line.decor);
3050
line_style.line.color = LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x171717) : 0x343434);
3051
3052
line_sep = lv_line_create(h1, line_sep);
3053
lv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 16);
3054
lv_line_set_style(line_sep, &line_style);
3055
3056
// Create HW info button.
3057
lv_obj_t *btn3 = lv_btn_create(h1, btn);
3058
label_btn = lv_label_create(btn3, NULL);
3059
lv_btn_set_fit(btn3, true, true);
3060
lv_label_set_static_text(label_btn, SYMBOL_CIRCUIT" HW & Fuses");
3061
lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 2);
3062
lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_window_hw_info_status);
3063
3064
// Create KFuses button.
3065
lv_obj_t *btn4 = lv_btn_create(h1, btn);
3066
label_btn = lv_label_create(btn4, NULL);
3067
lv_label_set_static_text(label_btn, SYMBOL_SHUFFLE" KFuses");
3068
lv_obj_align(btn4, btn3, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 46 / 100, 0);
3069
lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _kfuse_dump_window_action);
3070
3071
lv_obj_t *label_txt4 = lv_label_create(h1, NULL);
3072
lv_label_set_recolor(label_txt4, true);
3073
lv_label_set_static_text(label_txt4,
3074
"View and dump the cached #C7EA46 Fuses# and #C7EA46 KFuses#.\n"
3075
"Fuses contain info about the SoC/SKU and KFuses HDCP keys.\n"
3076
"You can also see info about #C7EA46 DRAM#, #C7EA46 Screen# and #C7EA46 Touch panel#.");
3077
lv_obj_set_style(label_txt4, &hint_small_style);
3078
lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
3079
3080
// Create Storage & Battery Info container.
3081
lv_obj_t *h2 = lv_cont_create(parent, NULL);
3082
lv_cont_set_style(h2, &h_style);
3083
lv_cont_set_fit(h2, false, true);
3084
lv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);
3085
lv_obj_set_click(h2, false);
3086
lv_cont_set_layout(h2, LV_LAYOUT_OFF);
3087
lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);
3088
3089
label_sep = lv_label_create(h2, NULL);
3090
lv_label_set_static_text(label_sep, "");
3091
3092
lv_obj_t *label_txt3 = lv_label_create(h2, NULL);
3093
lv_label_set_static_text(label_txt3, "Storage & Battery Info");
3094
lv_obj_set_style(label_txt3, th->label.prim);
3095
lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, 0);
3096
3097
line_sep = lv_line_create(h2, line_sep);
3098
lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 2), LV_DPI / 8);
3099
lv_line_set_style(line_sep, th->line.decor);
3100
3101
// Create eMMC button.
3102
lv_obj_t *btn5 = lv_btn_create(h2, NULL);
3103
if (hekate_bg)
3104
{
3105
lv_btn_set_style(btn5, LV_BTN_STYLE_REL, &btn_transp_rel);
3106
lv_btn_set_style(btn5, LV_BTN_STYLE_PR, &btn_transp_pr);
3107
}
3108
label_btn = lv_label_create(btn5, NULL);
3109
lv_btn_set_fit(btn5, true, true);
3110
lv_label_set_static_text(label_btn, SYMBOL_CHIP" eMMC ");
3111
lv_obj_align(btn5, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 2, LV_DPI / 4);
3112
lv_btn_set_action(btn5, LV_BTN_ACTION_CLICK, _create_window_emmc_info_status);
3113
3114
// Create microSD button.
3115
lv_obj_t *btn6 = lv_btn_create(h2, btn);
3116
label_btn = lv_label_create(btn6, NULL);
3117
lv_label_set_static_text(label_btn, SYMBOL_SD" microSD ");
3118
lv_obj_align(btn6, btn5, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 3 / 4, 0);
3119
lv_btn_set_action(btn6, LV_BTN_ACTION_CLICK, _create_window_sdcard_info_status);
3120
3121
lv_obj_t *label_txt5 = lv_label_create(h2, NULL);
3122
lv_label_set_recolor(label_txt5, true);
3123
lv_label_set_static_text(label_txt5,
3124
"View info about the eMMC or microSD and their partition list.\n"
3125
"Additionally you can benchmark read speeds.");
3126
lv_obj_set_style(label_txt5, &hint_small_style);
3127
lv_obj_align(label_txt5, btn5, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
3128
3129
line_sep = lv_line_create(h2, line_sep);
3130
lv_obj_align(line_sep, label_txt5, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 2);
3131
lv_line_set_style(line_sep, &line_style);
3132
3133
// Create Battery button.
3134
lv_obj_t *btn7 = lv_btn_create(h2, NULL);
3135
if (hekate_bg)
3136
{
3137
lv_btn_set_style(btn7, LV_BTN_STYLE_REL, &btn_transp_rel);
3138
lv_btn_set_style(btn7, LV_BTN_STYLE_PR, &btn_transp_pr);
3139
}
3140
label_btn = lv_label_create(btn7, NULL);
3141
lv_btn_set_fit(btn7, true, true);
3142
lv_label_set_static_text(label_btn, SYMBOL_BATTERY_FULL" Battery");
3143
lv_obj_align(btn7, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 2);
3144
lv_btn_set_action(btn7, LV_BTN_ACTION_CLICK, _create_window_battery_status);
3145
3146
lv_obj_t *label_txt6 = lv_label_create(h2, NULL);
3147
lv_label_set_recolor(label_txt6, true);
3148
lv_label_set_static_text(label_txt6,
3149
"View battery and battery charger related info.\n"
3150
"Additionally you can dump battery charger's registers.\n");
3151
lv_obj_set_style(label_txt6, &hint_small_style);
3152
lv_obj_align(label_txt6, btn7, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
3153
}
3154
3155