Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/storage/emmc.c
1476 views
1
/*
2
* Copyright (c) 2018 naehrwert
3
* Copyright (c) 2019-2024 CTCaer
4
*
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms and conditions of the GNU General Public License,
7
* version 2, as published by the Free Software Foundation.
8
*
9
* This program is distributed in the hope it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
* more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
#include <string.h>
19
20
#include "emmc.h"
21
#include <mem/heap.h>
22
#include <soc/fuse.h>
23
#include <storage/mbr_gpt.h>
24
#include <utils/list.h>
25
26
static u16 emmc_errors[3] = { 0 }; // Init and Read/Write errors.
27
static u32 emmc_mode = EMMC_MMC_HS400;
28
29
sdmmc_t emmc_sdmmc;
30
sdmmc_storage_t emmc_storage;
31
FATFS emmc_fs;
32
33
#ifdef BDK_EMUMMC_ENABLE
34
int emummc_storage_read(u32 sector, u32 num_sectors, void *buf);
35
int emummc_storage_write(u32 sector, u32 num_sectors, void *buf);
36
#endif
37
38
void emmc_error_count_increment(u8 type)
39
{
40
switch (type)
41
{
42
case EMMC_ERROR_INIT_FAIL:
43
emmc_errors[0]++;
44
break;
45
case EMMC_ERROR_RW_FAIL:
46
emmc_errors[1]++;
47
break;
48
case EMMC_ERROR_RW_RETRY:
49
emmc_errors[2]++;
50
break;
51
}
52
}
53
54
u16 *emmc_get_error_count()
55
{
56
return emmc_errors;
57
}
58
59
u32 emmc_get_mode()
60
{
61
return emmc_mode;
62
}
63
64
void emmc_end() { sdmmc_storage_end(&emmc_storage); }
65
66
int emmc_init_retry(bool power_cycle)
67
{
68
u32 bus_width = SDMMC_BUS_WIDTH_8;
69
u32 type = SDHCI_TIMING_MMC_HS400;
70
71
// Power cycle SD eMMC.
72
if (power_cycle)
73
{
74
emmc_mode--;
75
emmc_end();
76
}
77
78
// Get init parameters.
79
switch (emmc_mode)
80
{
81
case EMMC_INIT_FAIL: // Reset to max.
82
return 0;
83
case EMMC_1BIT_HS52:
84
bus_width = SDMMC_BUS_WIDTH_1;
85
type = SDHCI_TIMING_MMC_HS52;
86
break;
87
case EMMC_8BIT_HS52:
88
type = SDHCI_TIMING_MMC_HS52;
89
break;
90
case EMMC_MMC_HS200:
91
type = SDHCI_TIMING_MMC_HS200;
92
break;
93
case EMMC_MMC_HS400:
94
type = SDHCI_TIMING_MMC_HS400;
95
break;
96
default:
97
emmc_mode = EMMC_MMC_HS400;
98
}
99
100
return sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, bus_width, type);
101
}
102
103
bool emmc_initialize(bool power_cycle)
104
{
105
// Reset mode in case of previous failure.
106
if (emmc_mode == EMMC_INIT_FAIL)
107
emmc_mode = EMMC_MMC_HS400;
108
109
if (power_cycle)
110
emmc_end();
111
112
int res = !emmc_init_retry(false);
113
114
while (true)
115
{
116
if (!res)
117
return true;
118
else
119
{
120
emmc_errors[EMMC_ERROR_INIT_FAIL]++;
121
122
if (emmc_mode == EMMC_INIT_FAIL)
123
break;
124
else
125
res = !emmc_init_retry(true);
126
}
127
}
128
129
emmc_end();
130
131
return false;
132
}
133
134
int emmc_set_partition(u32 partition) { return sdmmc_storage_set_mmc_partition(&emmc_storage, partition); }
135
136
void emmc_gpt_parse(link_t *gpt)
137
{
138
gpt_t *gpt_buf = (gpt_t *)zalloc(GPT_NUM_BLOCKS * EMMC_BLOCKSIZE);
139
140
#ifdef BDK_EMUMMC_ENABLE
141
emummc_storage_read(GPT_FIRST_LBA, GPT_NUM_BLOCKS, gpt_buf);
142
#else
143
sdmmc_storage_read(&emmc_storage, GPT_FIRST_LBA, GPT_NUM_BLOCKS, gpt_buf);
144
#endif
145
146
// Check if no GPT or more than max allowed entries.
147
if (memcmp(&gpt_buf->header.signature, "EFI PART", 8) || gpt_buf->header.num_part_ents > 128)
148
goto out;
149
150
for (u32 i = 0; i < gpt_buf->header.num_part_ents; i++)
151
{
152
emmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t));
153
154
if (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba)
155
continue;
156
157
part->index = i;
158
part->lba_start = gpt_buf->entries[i].lba_start;
159
part->lba_end = gpt_buf->entries[i].lba_end;
160
part->attrs = gpt_buf->entries[i].attrs;
161
162
// ASCII conversion. Copy only the LSByte of the UTF-16LE name.
163
for (u32 j = 0; j < 36; j++)
164
part->name[j] = gpt_buf->entries[i].name[j];
165
part->name[35] = 0;
166
167
list_append(gpt, &part->link);
168
}
169
170
out:
171
free(gpt_buf);
172
}
173
174
void emmc_gpt_free(link_t *gpt)
175
{
176
LIST_FOREACH_SAFE(iter, gpt)
177
free(CONTAINER_OF(iter, emmc_part_t, link));
178
}
179
180
emmc_part_t *emmc_part_find(link_t *gpt, const char *name)
181
{
182
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)
183
if (!strcmp(part->name, name))
184
return part;
185
186
return NULL;
187
}
188
189
int emmc_part_read(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
190
{
191
// The last LBA is inclusive.
192
if (part->lba_start + sector_off > part->lba_end)
193
return 0;
194
195
#ifdef BDK_EMUMMC_ENABLE
196
return emummc_storage_read(part->lba_start + sector_off, num_sectors, buf);
197
#else
198
return sdmmc_storage_read(&emmc_storage, part->lba_start + sector_off, num_sectors, buf);
199
#endif
200
}
201
202
int emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
203
{
204
// The last LBA is inclusive.
205
if (part->lba_start + sector_off > part->lba_end)
206
return 0;
207
208
#ifdef BDK_EMUMMC_ENABLE
209
return emummc_storage_write(part->lba_start + sector_off, num_sectors, buf);
210
#else
211
return sdmmc_storage_write(&emmc_storage, part->lba_start + sector_off, num_sectors, buf);
212
#endif
213
}
214
215
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)
216
{
217
if (fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD)
218
{
219
*mod0 = 0xF7;
220
*mod1 = 0x86;
221
}
222
else
223
{
224
*mod0 = 0x37;
225
*mod1 = 0x84;
226
}
227
}
228
229