Apply hekate 5.2.1 and gcc 10 changes, -fno-inline

This commit is contained in:
shchmue 2020-05-18 14:11:27 -06:00
parent a5fe954ce7
commit 64d7e5cebd
64 changed files with 4676 additions and 3360 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 CTCaer
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -24,17 +24,12 @@
#include "../gfx/gfx.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../storage/nx_sd.h"
#include "../utils/list.h"
#include "../utils/types.h"
extern sdmmc_t sd_sdmmc;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
extern hekate_config h_cfg;
extern bool sd_mount();
extern void sd_unmount();
emummc_cfg_t emu_cfg;
bool emummc_load_cfg()
{
@ -47,7 +42,8 @@ bool emummc_load_cfg()
emu_cfg.file_based_part_size = 0;
emu_cfg.active_part = 0;
emu_cfg.fs_ver = 0;
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
if (!emu_cfg.emummc_file_based_path)
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
@ -94,18 +90,14 @@ static int emummc_raw_get_part_off(int part_idx)
return 2;
}
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
{
FILINFO fno;
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
return 2;
goto out;
}
if (h_cfg.emummc_force_disable)
return 1;
return 0;
emu_cfg.active_part = 0;
if (!sd_mount())
@ -131,10 +123,11 @@ int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
}
emu_cfg.file_based_part_size = fno.fsize >> 9;
}
return 1;
return 0;
out:
return 0;
return 1;
}
int emummc_storage_end(sdmmc_storage_t *storage)

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 CTCaer
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -47,7 +47,7 @@ typedef struct _emummc_cfg_t
int fs_ver;
} emummc_cfg_t;
emummc_cfg_t emu_cfg;
extern emummc_cfg_t emu_cfg;
bool emummc_load_cfg();
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);

84
source/storage/mbr_gpt.h Normal file
View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MBR_GPT_H
#define MBR_GPT_H
#include "../utils/types.h"
typedef struct _mbr_chs_t
{
u8 head;
u8 sector;
u8 cylinder;
} __attribute__((packed)) mbr_chs_t;
typedef struct _mbr_part_t
{
u8 status;
mbr_chs_t start_sct_chs;
u8 type;
mbr_chs_t end_sct_chs;
u32 start_sct;
u32 size_sct;
} __attribute__((packed)) mbr_part_t;
typedef struct _mbr_t
{
u8 bootstrap[440];
u32 signature;
u16 copy_protected;
mbr_part_t partitions[4];
u16 boot_signature;
} __attribute__((packed)) mbr_t;
typedef struct _gpt_entry_t
{
u8 type_guid[0x10];
u8 part_guid[0x10];
u64 lba_start;
u64 lba_end;
u64 attrs;
u16 name[36];
} gpt_entry_t;
typedef struct _gpt_header_t
{
u64 signature; // "EFI PART"
u32 revision;
u32 size;
u32 crc32;
u32 res1;
u64 my_lba;
u64 alt_lba;
u64 first_use_lba;
u64 last_use_lba;
u8 disk_guid[0x10];
u64 part_ent_lba;
u32 num_part_ents;
u32 part_ent_size;
u32 part_ents_crc32;
u8 res2[420]; // Used as first 3 partition entries backup for HOS.
} gpt_header_t;
typedef struct _gpt_t
{
gpt_header_t header;
gpt_entry_t entries[128];
} gpt_t;
#endif

View file

@ -16,6 +16,7 @@
#include <string.h>
#include "mbr_gpt.h"
#include "nx_emmc.h"
#include "emummc.h"
#include "../mem/heap.h"
@ -23,28 +24,31 @@
void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
{
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE);
gpt_t *gpt_buf = (gpt_t *)calloc(NX_GPT_NUM_BLOCKS, NX_EMMC_BLOCKSIZE);
emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, gpt_buf);
gpt_header_t *hdr = (gpt_header_t *)buf;
for (u32 i = 0; i < hdr->num_part_ents; i++)
for (u32 i = 0; i < gpt_buf->header.num_part_ents; i++)
{
gpt_entry_t *ent = (gpt_entry_t *)(buf + (hdr->part_ent_lba - 1) * NX_EMMC_BLOCKSIZE + i * sizeof(gpt_entry_t));
emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1);
part->lba_start = ent->lba_start;
part->lba_end = ent->lba_end;
part->attrs = ent->attrs;
if (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba)
continue;
part->index = i;
part->lba_start = gpt_buf->entries[i].lba_start;
part->lba_end = gpt_buf->entries[i].lba_end;
part->attrs = gpt_buf->entries[i].attrs;
// ASCII conversion. Copy only the LSByte of the UTF-16LE name.
for (u32 i = 0; i < 36; i++)
part->name[i] = ent->name[i];
part->name[36] = 0;
for (u32 j = 0; j < 36; j++)
part->name[j] = gpt_buf->entries[i].name[j];
part->name[35] = 0;
list_append(gpt, &part->link);
}
free(buf);
free(gpt_buf);
}
void nx_emmc_gpt_free(link_t *gpt)

View file

@ -17,38 +17,9 @@
#ifndef _NX_EMMC_H_
#define _NX_EMMC_H_
#include "sdmmc.h"
#include "../utils/types.h"
#include "../utils/list.h"
#include "sdmmc.h"
typedef struct _gpt_entry_t
{
u8 type_guid[0x10];
u8 part_guid[0x10];
u64 lba_start;
u64 lba_end;
u64 attrs;
u16 name[36];
} gpt_entry_t;
typedef struct _gpt_header_t
{
u64 signature;
u32 revision;
u32 size;
u32 crc32;
u32 res1;
u64 my_lba;
u64 alt_lba;
u64 first_use_lba;
u64 last_use_lba;
u8 disk_guid[0x10];
u64 part_ent_lba;
u32 num_part_ents;
u32 part_ent_size;
u32 part_ents_crc32;
u8 res2[420];
} gpt_header_t;
#define NX_GPT_FIRST_LBA 1
#define NX_GPT_NUM_BLOCKS 33
@ -56,6 +27,7 @@ typedef struct _gpt_header_t
typedef struct _emmc_part_t
{
u32 index;
u32 lba_start;
u32 lba_end;
u64 attrs;

184
source/storage/nx_sd.c Normal file
View file

@ -0,0 +1,184 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nx_sd.h"
#include "sdmmc.h"
#include "sdmmc_driver.h"
#include "../gfx/gfx.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
static bool sd_mounted = false;
static u32 sd_mode = SD_UHS_SDR82;
sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage;
FATFS sd_fs;
u32 sd_get_mode()
{
return sd_mode;
}
int sd_init_retry(bool power_cycle)
{
u32 bus_width = SDMMC_BUS_WIDTH_4;
u32 type = SDHCI_TIMING_UHS_SDR82;
// Power cycle SD card.
if (power_cycle)
{
sd_mode--;
sdmmc_storage_end(&sd_storage);
}
// Get init parameters.
switch (sd_mode)
{
case SD_INIT_FAIL: // Reset to max.
return 0;
case SD_1BIT_HS25:
bus_width = SDMMC_BUS_WIDTH_1;
type = SDHCI_TIMING_SD_HS25;
break;
case SD_4BIT_HS25:
type = SDHCI_TIMING_SD_HS25;
break;
case SD_UHS_SDR82:
type = SDHCI_TIMING_UHS_SDR82;
break;
default:
sd_mode = SD_UHS_SDR82;
}
return sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, bus_width, type);
}
bool sd_initialize(bool power_cycle)
{
if (power_cycle)
sdmmc_storage_end(&sd_storage);
int res = !sd_init_retry(false);
while (true)
{
if (!res)
return true;
else if (!sdmmc_get_sd_inserted()) // SD Card is not inserted.
{
sd_mode = SD_UHS_SDR82;
break;
}
else if (sd_mode == SD_INIT_FAIL)
break;
else
res = !sd_init_retry(true);
}
sdmmc_storage_end(&sd_storage);
return false;
}
bool sd_mount()
{
if (sd_mounted)
return true;
int res = !sd_initialize(false);
if (res)
{
gfx_con.mute = false;
EPRINTF("Failed to init SD card.");
if (!sdmmc_get_sd_inserted())
EPRINTF("Make sure that it is inserted.");
else
EPRINTF("SD Card Reader is not properly seated!");
}
else
{
res = f_mount(&sd_fs, "", 1);
if (res == FR_OK)
{
sd_mounted = true;
return true;
}
else
{
gfx_con.mute = false;
EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
}
}
return false;
}
void sd_unmount()
{
sd_mode = SD_UHS_SDR82;
if (sd_mounted)
{
f_mount(NULL, "", 1);
sdmmc_storage_end(&sd_storage);
sd_mounted = false;
}
}
void *sd_file_read(const char *path, u32 *fsize)
{
FIL fp;
if (f_open(&fp, path, FA_READ) != FR_OK)
return NULL;
u32 size = f_size(&fp);
if (fsize)
*fsize = size;
void *buf = malloc(size);
if (f_read(&fp, buf, size, NULL) != FR_OK)
{
free(buf);
f_close(&fp);
return NULL;
}
f_close(&fp);
return buf;
}
int sd_save_to_file(void *buf, u32 size, const char *filename)
{
FIL fp;
u32 res = 0;
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
return res;
}
f_write(&fp, buf, size, NULL);
f_close(&fp);
return 0;
}

45
source/storage/nx_sd.h Normal file
View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NX_SD_H
#define NX_SD_H
#include "sdmmc.h"
#include "sdmmc_driver.h"
#include "../libs/fatfs/ff.h"
enum
{
SD_INIT_FAIL = 0,
SD_1BIT_HS25 = 1,
SD_4BIT_HS25 = 2,
SD_UHS_SDR82 = 3,
};
extern sdmmc_t sd_sdmmc;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
u32 sd_get_mode();
int sd_init_retry(bool power_cycle);
bool sd_initialize(bool power_cycle);
bool sd_mount();
void sd_unmount();
void *sd_file_read(const char *path, u32 *fsize);
int sd_save_to_file(void *buf, u32 size, const char *filename);
#endif

View file

@ -106,6 +106,11 @@
#define SD_SET_CURRENT_LIMIT_600 2
#define SD_SET_CURRENT_LIMIT_800 3
#define SD_MAX_CURRENT_200 (1 << SD_SET_CURRENT_LIMIT_200)
#define SD_MAX_CURRENT_400 (1 << SD_SET_CURRENT_LIMIT_400)
#define SD_MAX_CURRENT_600 (1 << SD_SET_CURRENT_LIMIT_600)
#define SD_MAX_CURRENT_800 (1 << SD_SET_CURRENT_LIMIT_800)
/*
* SD_SWITCH mode
*/

View file

@ -18,6 +18,7 @@
#include <string.h>
#include "sdmmc.h"
#include "mmc.h"
#include "nx_sd.h"
#include "sd.h"
#include "../../common/memory_map.h"
#include "../gfx/gfx.h"
@ -135,10 +136,12 @@ static int _sdmmc_storage_check_status(sdmmc_storage_t *storage)
static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write)
{
u32 tmp = 0;
sdmmc_cmd_t cmdbuf;
sdmmc_req_t reqbuf;
sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0);
sdmmc_req_t reqbuf;
reqbuf.buf = buf;
reqbuf.num_sectors = num_sectors;
reqbuf.blksize = 512;
@ -148,7 +151,6 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out))
{
u32 tmp = 0;
sdmmc_stop_transmission(storage->sdmmc, &tmp);
_sdmmc_storage_get_status(storage, &tmp, 0);
@ -171,25 +173,42 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write)
{
u8 *bbuf = (u8 *)buf;
bool first_reinit = false;
while (num_sectors)
{
u32 blkcnt = 0;
//Retry 9 times on error.
u32 retries = 10;
// Retry 5 times if failed.
u32 retries = 5;
do
{
reinit_try:
if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sector, MIN(num_sectors, 0xFFFF), bbuf, is_write))
goto out;
else
retries--;
msleep(100);
msleep(50);
} while (retries);
// Disk IO failure! Reinit SD Card to a lower speed.
if (storage->sdmmc->id == SDMMC_1)
{
int res;
if (!first_reinit)
res = sd_initialize(true);
else
res = sd_init_retry(true);
retries = 3;
first_reinit = true;
if (res)
goto reinit_try;
}
return 0;
out:;
out:
DPRINTF("readwrite: %08X\n", blkcnt);
sector += blkcnt;
num_sectors -= blkcnt;
@ -201,12 +220,34 @@ DPRINTF("readwrite: %08X\n", blkcnt);
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
{
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0);
// Ensure that buffer resides in DRAM and it's DMA aligned.
if (((u32)buf >= DRAM_START) && !((u32)buf % 8))
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0);
if (num_sectors > (SDMMC_UP_BUF_SZ / 512))
return 0;
u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER;
if (_sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 0))
{
memcpy(buf, tmp_buf, 512 * num_sectors);
return 1;
}
return 0;
}
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
{
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1);
// Ensure that buffer resides in DRAM and it's DMA aligned.
if (((u32)buf >= DRAM_START) && !((u32)buf % 8))
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1);
if (num_sectors > (SDMMC_UP_BUF_SZ / 512))
return 0;
u8 *tmp_buf = (u8 *)SDMMC_UPPER_BUFFER;
memcpy(tmp_buf, buf, 512 * num_sectors);
return _sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 1);
}
/*
@ -401,7 +442,7 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check)
if (check && !_sdmmc_storage_check_status(storage))
return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 2))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52))
return 0;
DPRINTF("[MMC] switched to HS\n");
@ -418,10 +459,10 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage)
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 3))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200))
return 0;
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200))
return 0;
DPRINTF("[MMC] switched to HS200\n");
@ -435,7 +476,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
if (!_mmc_storage_enable_HS200(storage))
return 0;
sdmmc_get_venclkctl(storage->sdmmc);
sdmmc_set_tap_value(storage->sdmmc);
if (!_mmc_storage_enable_HS(storage, 0))
return 0;
@ -446,7 +487,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
return 0;
if (!sdmmc_setup_clock(storage->sdmmc, 4))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400))
return 0;
DPRINTF("[MMC] switched to HS400\n");
@ -457,22 +498,20 @@ DPRINTF("[MMC] switched to HS400\n");
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
{
//TODO: this should be a config item.
// --v
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
if (sdmmc_get_io_power(storage->sdmmc) != SDMMC_POWER_1_8)
goto out;
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4)
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400)
return _mmc_storage_enable_HS400(storage);
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
(sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4
&& card_type & EXT_CSD_CARD_TYPE_HS200_1_8V
&& (type == 4 || type == 3)))
&& (type == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200)))
return _mmc_storage_enable_HS200(storage);
out:;
out:
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
return _mmc_storage_enable_HS(storage, 1);
@ -487,13 +526,13 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage)
return _sdmmc_storage_check_status(storage);
}
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
{
memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc;
storage->rca = 2; //TODO: this could be a config item.
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0))
if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_AUTO_CAL_DISABLE))
return 0;
DPRINTF("[MMC] after init\n");
@ -520,7 +559,7 @@ DPRINTF("[MMC] set relative addr\n");
DPRINTF("[MMC] got csd\n");
_mmc_storage_parse_csd(storage);
if (!sdmmc_setup_clock(storage->sdmmc, 1))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26))
return 0;
DPRINTF("[MMC] after setup clock\n");
@ -544,35 +583,27 @@ DPRINTF("[MMC] set blocklen to 512\n");
return 0;
DPRINTF("[MMC] switched buswidth\n");
u8 *ext_csd = (u8 *)malloc(512);
if (!_mmc_storage_get_ext_csd(storage, ext_csd))
{
free(ext_csd);
if (!_mmc_storage_get_ext_csd(storage, (u8 *)SDMMC_UPPER_BUFFER))
return 0;
}
free(ext_csd);
DPRINTF("[MMC] got ext_csd\n");
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
//gfx_hexdump(0, ext_csd, 512);
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
Additionally this works only when we put the device in idle mode which we don't after enabling it. */
if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0)
if (0 && storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2))
{
_mmc_storage_enable_bkops(storage);
DPRINTF("[MMC] BKOPS enabled\n");
}
else
{
DPRINTF("[MMC] BKOPS disabled\n");
}
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
return 0;
DPRINTF("[MMC] succesfully switched to HS mode\n");
sdmmc_sd_clock_ctrl(storage->sdmmc, 1);
sdmmc_card_clock_ctrl(storage->sdmmc, SDMMC_AUTO_CAL_ENABLE);
return 1;
}
@ -656,6 +687,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
if (cond & SD_OCR_CCS)
storage->has_sector_access = 1;
// Check if card supports 1.8V signaling.
if (cond & SD_ROCR_S18A && supports_low_voltage)
{
//The low voltage regulator configuration is valid for SDMMC1 only.
@ -804,34 +836,37 @@ int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group,
return _sdmmc_storage_check_result(tmp);
}
void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf)
void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u16 current_limit, u8 *buf)
{
u32 pwr = SD_SET_CURRENT_LIMIT_800;
u32 pwr = SD_SET_CURRENT_LIMIT_200;
if (current_limit & SD_MAX_CURRENT_800)
pwr = SD_SET_CURRENT_LIMIT_800;
else if (current_limit & SD_MAX_CURRENT_600)
pwr = SD_SET_CURRENT_LIMIT_600;
else if (current_limit & SD_MAX_CURRENT_400)
pwr = SD_SET_CURRENT_LIMIT_400;
_sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr);
while (pwr > 0)
if (((buf[15] >> 4) & 0x0F) == pwr)
{
pwr--;
_sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr);
if (((buf[15] >> 4) & 0x0F) == pwr)
switch (pwr)
{
case SD_SET_CURRENT_LIMIT_800:
DPRINTF("[SD] power limit raised to 800mA\n");
break;
}
switch (pwr)
{
case SD_SET_CURRENT_LIMIT_800:
DPRINTF("[SD] power limit raised to 800mA\n");
break;
case SD_SET_CURRENT_LIMIT_600:
case SD_SET_CURRENT_LIMIT_600:
DPRINTF("[SD] power limit raised to 600mA\n");
break;
case SD_SET_CURRENT_LIMIT_400:
DPRINTF("[SD] power limit raised to 800mA\n");
break;
default:
case SD_SET_CURRENT_LIMIT_200:
break;
case SD_SET_CURRENT_LIMIT_400:
DPRINTF("[SD] power limit raised to 400mA\n");
break;
default:
case SD_SET_CURRENT_LIMIT_200:
DPRINTF("[SD] power limit defaulted to 200mA\n");
break;
break;
}
}
}
@ -839,30 +874,33 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)
{
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
return 0;
DPRINTF("[SD] SD supports switch to (U)HS check\n");
DPRINTF("[SD] supports switch to (U)HS mode\n");
u32 type_out = buf[16] & 0xF;
if (type_out != hs_type)
return 0;
DPRINTF("[SD] SD supports selected (U)HS mode\n");
DPRINTF("[SD] supports selected (U)HS mode\n");
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];
DPRINTF("[SD] total max current: %d\n", total_pwr_consumption);
if (total_pwr_consumption <= 800)
{
if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type))
return 0;
if (type_out != (buf[16] & 0xF))
return 0;
}
return 1;
return 1;
}
DPRINTF("[SD] card max current over limit\n");
return 0;
}
int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
{
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, buf);
if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4)
return 0;
@ -870,32 +908,55 @@ int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
return 0;
//gfx_hexdump(0, (u8 *)buf, 64);
u8 access_mode = buf[13];
u16 current_limit = buf[7] | buf[6] << 8;
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, current_limit, buf);
u32 hs_type = 0;
switch (type)
{
case 11: // SDR104.
case SDHCI_TIMING_UHS_SDR104:
case SDHCI_TIMING_UHS_SDR82:
// Fall through if not supported.
if (buf[13] & SD_MODE_UHS_SDR104)
if (access_mode & SD_MODE_UHS_SDR104)
{
type = 11;
hs_type = UHS_SDR104_BUS_SPEED;
DPRINTF("[SD] bus speed set to SDR104\n");
storage->csd.busspeed = 104;
switch (type)
{
case SDHCI_TIMING_UHS_SDR104:
storage->csd.busspeed = 104;
break;
case SDHCI_TIMING_UHS_SDR82:
storage->csd.busspeed = 82;
break;
}
break;
}
case 10: // SDR50.
if (buf[13] & SD_MODE_UHS_SDR50)
case SDHCI_TIMING_UHS_SDR50:
if (access_mode & SD_MODE_UHS_SDR50)
{
type = 10;
type = SDHCI_TIMING_UHS_SDR50;
hs_type = UHS_SDR50_BUS_SPEED;
DPRINTF("[SD] bus speed set to SDR50\n");
storage->csd.busspeed = 50;
break;
}
case 8: // SDR12.
if (!(buf[13] & SD_MODE_UHS_SDR12))
case SDHCI_TIMING_UHS_SDR25:
if (access_mode & SD_MODE_UHS_SDR25)
{
type = SDHCI_TIMING_UHS_SDR25;
hs_type = UHS_SDR50_BUS_SPEED;
DPRINTF("[SD] bus speed set to SDR25\n");
storage->csd.busspeed = 25;
break;
}
case SDHCI_TIMING_UHS_SDR12:
if (!(access_mode & SD_MODE_UHS_SDR12))
return 0;
type = 8;
type = SDHCI_TIMING_UHS_SDR12;
hs_type = UHS_SDR12_BUS_SPEED;
DPRINTF("[SD] bus speed set to SDR12\n");
storage->csd.busspeed = 12;
@ -907,11 +968,11 @@ DPRINTF("[SD] bus speed set to SDR12\n");
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
return 0;
DPRINTF("[SD] SD card accepted UHS\n");
DPRINTF("[SD] card accepted UHS\n");
if (!sdmmc_setup_clock(storage->sdmmc, type))
return 0;
DPRINTF("[SD] setup clock\n");
if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
return 0;
DPRINTF("[SD] config tuning\n");
return _sdmmc_storage_check_status(storage);
@ -922,16 +983,23 @@ int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf)
if (!_sd_storage_switch_get(storage, buf))
return 0;
//gfx_hexdump(0, (u8 *)buf, 64);
if (!(buf[13] & SD_MODE_HIGH_SPEED))
u8 access_mode = buf[13];
u16 current_limit = buf[7] | buf[6] << 8;
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, current_limit, buf);
if (!(access_mode & SD_MODE_HIGH_SPEED))
return 1;
if (!_sd_storage_enable_highspeed(storage, 1, buf))
if (!_sd_storage_enable_highspeed(storage, HIGH_SPEED_BUS_SPEED, buf))
return 0;
if (!_sdmmc_storage_check_status(storage))
return 0;
return sdmmc_setup_clock(storage->sdmmc, 7);
return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25);
}
static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
@ -1055,6 +1123,23 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
}
}
static bool _sdmmc_storage_supports_low_voltage(u32 bus_width, u32 type)
{
switch (type)
{
case SDHCI_TIMING_UHS_SDR12:
case SDHCI_TIMING_UHS_SDR25:
case SDHCI_TIMING_UHS_SDR50:
case SDHCI_TIMING_UHS_SDR104:
case SDHCI_TIMING_UHS_SDR82:
case SDHCI_TIMING_UHS_DDR50:
if (bus_width == SDMMC_BUS_WIDTH_4)
return true;
default:
return false;
}
}
void sdmmc_storage_init_wait_sd()
{
u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start;
@ -1062,7 +1147,7 @@ void sdmmc_storage_init_wait_sd()
msleep(100 - sd_poweroff_time);
}
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
{
int is_version_1 = 0;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
@ -1073,7 +1158,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc;
if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0))
if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_AUTO_CAL_DISABLE))
return 0;
DPRINTF("[SD] after init\n");
@ -1088,7 +1173,9 @@ DPRINTF("[SD] went to idle state\n");
return 0;
DPRINTF("[SD] after send if cond\n");
if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11))
bool supports_low_voltage = _sdmmc_storage_supports_low_voltage(bus_width, type);
if (!_sd_storage_get_op_cond(storage, is_version_1, supports_low_voltage))
return 0;
DPRINTF("[SD] got op cond\n");
@ -1122,7 +1209,7 @@ DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
if (!storage->is_low_voltage)
{
if (!sdmmc_setup_clock(storage->sdmmc, 6))
if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12))
return 0;
DPRINTF("[SD] after setup clock\n");
}
@ -1165,18 +1252,26 @@ DPRINTF("[SD] SD does not support wide bus width\n");
if (!_sd_storage_enable_uhs_low_volt(storage, type, buf))
return 0;
DPRINTF("[SD] enabled UHS\n");
sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
}
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0)
{
if (!_sd_storage_enable_hs_high_volt(storage, buf))
return 0;
DPRINTF("[SD] enabled HS\n");
storage->csd.busspeed = 25;
switch (bus_width)
{
case SDMMC_BUS_WIDTH_4:
storage->csd.busspeed = 25;
break;
case SDMMC_BUS_WIDTH_1:
storage->csd.busspeed = 6;
break;
}
}
sdmmc_sd_clock_ctrl(sdmmc, 1);
// Parse additional card info from sd status.
if (_sd_storage_get_ssr(storage, buf))
{
@ -1222,17 +1317,17 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc;
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0))
if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_DDR52, SDMMC_AUTO_CAL_DISABLE))
return 0;
DPRINTF("[gc] after init\n");
usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor);
if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200))
if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_DDR52, MMC_SEND_TUNING_BLOCK_HS200))
return 0;
DPRINTF("[gc] after tuning\n");
sdmmc_sd_clock_ctrl(sdmmc, 1);
sdmmc_card_clock_ctrl(sdmmc, SDMMC_AUTO_CAL_ENABLE);
return 1;
}

View file

@ -21,7 +21,17 @@
#include "../utils/types.h"
#include "sdmmc_driver.h"
u32 sd_power_cycle_time_start;
extern u32 sd_power_cycle_time_start;
typedef enum _sdmmc_type
{
MMC_SD = 0,
MMC_EMMC = 1,
EMMC_GPP = 0,
EMMC_BOOT0 = 1,
EMMC_BOOT1 = 2
} sdmmc_type;
typedef struct _mmc_cid
{
@ -107,10 +117,10 @@ typedef struct _sdmmc_storage_t
int sdmmc_storage_end(sdmmc_storage_t *storage);
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
void sdmmc_storage_init_wait_sd();
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -49,24 +50,158 @@
#define SDMMC_MASKINT_NOERROR -1
#define SDMMC_MASKINT_ERROR -2
/*! SDMMC host control 2 */
#define SDHCI_CTRL_UHS_MASK 0xFFF8
#define SDHCI_CTRL_VDD_330 0xFFF7
#define SDHCI_CTRL_VDD_180 8
#define SDHCI_CTRL_EXEC_TUNING 0x40
#define SDHCI_CTRL_TUNED_CLK 0x80
#define SDHCI_HOST_VERSION_4_EN 0x1000
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000
/*! SDMMC present state. */
#define SDHCI_CMD_INHIBIT 0x1
#define SDHCI_DATA_INHIBIT 0x2
#define SDHCI_DOING_WRITE 0x100
#define SDHCI_DOING_READ 0x200
#define SDHCI_SPACE_AVAILABLE 0x400
#define SDHCI_DATA_AVAILABLE 0x800
#define SDHCI_CARD_PRESENT 0x10000
#define SDHCI_CD_STABLE 0x20000
#define SDHCI_CD_LVL 0x40000
#define SDHCI_WRITE_PROTECT 0x80000
#define SDHCI_DATA_LVL_MASK 0xF00000
#define SDHCI_DATA_0_LVL_MASK 0x100000
#define SDHCI_CMD_LVL 0x1000000
/*! SDMMC transfer mode. */
#define SDHCI_TRNS_DMA 0x01
#define SDHCI_TRNS_BLK_CNT_EN 0x02
#define SDHCI_TRNS_AUTO_CMD12 0x04
#define SDHCI_TRNS_AUTO_CMD23 0x08
#define SDHCI_TRNS_AUTO_SEL 0x0C
#define SDHCI_TRNS_WRITE 0x00
#define SDHCI_TRNS_READ 0x10
#define SDHCI_TRNS_MULTI 0x20
/*! SDMMC command. */
#define SDHCI_CMD_RESP_MASK 0x3
#define SDHCI_CMD_RESP_NO_RESP 0x0
#define SDHCI_CMD_RESP_LEN136 0x1
#define SDHCI_CMD_RESP_LEN48 0x2
#define SDHCI_CMD_RESP_LEN48_BUSY 0x3
#define SDHCI_CMD_CRC 0x08
#define SDHCI_CMD_INDEX 0x10
#define SDHCI_CMD_DATA 0x20
#define SDHCI_CMD_ABORTCMD 0xC0
/*! SDMMC host control. */
#define SDHCI_CTRL_LED 0x01
#define SDHCI_CTRL_4BITBUS 0x02
#define SDHCI_CTRL_HISPD 0x04
#define SDHCI_CTRL_DMA_MASK 0x18
#define SDHCI_CTRL_SDMA 0x00
#define SDHCI_CTRL_ADMA1 0x08
#define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA64 0x18
#define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_CTRL_CDTEST_INS 0x40
#define SDHCI_CTRL_CDTEST_EN 0x80
/*! SDMMC host control 2. */
#define SDHCI_CTRL_UHS_MASK 0xFFF8
#define SDHCI_CTRL_VDD_180 8
#define SDHCI_CTRL_DRV_TYPE_B 0x00
#define SDHCI_CTRL_DRV_TYPE_A 0x10
#define SDHCI_CTRL_DRV_TYPE_C 0x20
#define SDHCI_CTRL_DRV_TYPE_D 0x30
#define SDHCI_CTRL_EXEC_TUNING 0x40
#define SDHCI_CTRL_TUNED_CLK 0x80
#define SDHCI_HOST_VERSION_4_EN 0x1000
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
#define SDHCI_CTRL_PRESET_VAL_EN 0x8000
/*! SDMMC power control. */
#define SDHCI_POWER_ON 0x01
#define SDHCI_POWER_180 0x0A
#define SDHCI_POWER_300 0x0C
#define SDHCI_POWER_330 0x0E
#define SDHCI_POWER_MASK 0xF1
// /*! SDMMC max current. */
// #define SDHCI_MAX_CURRENT_330_MASK 0xFF
// #define SDHCI_MAX_CURRENT_180_MASK 0xFF0000
// #define SDHCI_MAX_CURRENT_MULTIPLIER 4
/*! SDMMC clock control. */
#define SDHCI_DIVIDER_SHIFT 8
#define SDHCI_DIVIDER_HI_SHIFT 6
#define SDHCI_DIV_MASK 0xFF00
#define SDHCI_DIV_HI_MASK 0xC0
#define SDHCI_PROG_CLOCK_MODE 0x20
#define SDHCI_CLOCK_CARD_EN 0x4
#define SDHCI_CLOCK_INT_STABLE 0x2
#define SDHCI_CLOCK_INT_EN 0x1
/*! SDMMC software reset. */
#define SDHCI_RESET_ALL 0x01
#define SDHCI_RESET_CMD 0x02
#define SDHCI_RESET_DATA 0x04
/*! SDMMC interrupt status and control. */
#define SDHCI_INT_RESPONSE 0x1
#define SDHCI_INT_DATA_END 0x2
#define SDHCI_INT_BLK_GAP 0x4
#define SDHCI_INT_DMA_END 0x8
#define SDHCI_INT_SPACE_AVAIL 0x10
#define SDHCI_INT_DATA_AVAIL 0x20
#define SDHCI_INT_CARD_INSERT 0x40
#define SDHCI_INT_CARD_REMOVE 0x80
#define SDHCI_INT_CARD_INT 0x100
#define SDHCI_INT_RETUNE 0x1000
#define SDHCI_INT_CQE 0x4000
#define SDHCI_INT_ERROR 0x8000
/*! SDMMC error interrupt status and control. */
#define SDHCI_ERR_INT_TIMEOUT 0x1
#define SDHCI_ERR_INT_CRC 0x2
#define SDHCI_ERR_INT_END_BIT 0x4
#define SDHCI_ERR_INT_INDEX 0x8
#define SDHCI_ERR_INT_DATA_TIMEOUT 0x10
#define SDHCI_ERR_INT_DATA_CRC 0x20
#define SDHCI_ERR_INT_DATA_END_BIT 0x40
#define SDHCI_ERR_INT_BUS_POWER 0x80
#define SDHCI_ERR_INT_AUTO_CMD_ERR 0x100
#define SDHCI_ERR_INT_ADMA_ERROR 0x200
#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \
(SDHCI_ERR_INT_AUTO_CMD_ERR | SDHCI_ERR_INT_DATA_END_BIT | \
SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \
SDHCI_ERR_INT_INDEX | SDHCI_ERR_INT_END_BIT | \
SDHCI_ERR_INT_CRC | SDHCI_ERR_INT_TIMEOUT)
/*! SD bus speeds. */
#define UHS_SDR12_BUS_SPEED 0
#define HIGH_SPEED_BUS_SPEED 1
#define UHS_SDR25_BUS_SPEED 1
#define UHS_SDR50_BUS_SPEED 2
#define UHS_SDR104_BUS_SPEED 3
#define UHS_DDR50_BUS_SPEED 4
#define HS400_BUS_SPEED 5
#define UHS_SDR12_BUS_SPEED 0
#define HIGH_SPEED_BUS_SPEED 1
#define UHS_SDR25_BUS_SPEED 1
#define UHS_SDR50_BUS_SPEED 2
#define UHS_SDR104_BUS_SPEED 3
#define UHS_DDR50_BUS_SPEED 4
#define HS400_BUS_SPEED 5
/*! SDMMC timmings. */
#define SDHCI_TIMING_MMC_ID 0
#define SDHCI_TIMING_MMC_LS26 1
#define SDHCI_TIMING_MMC_HS52 2
#define SDHCI_TIMING_MMC_HS200 3
#define SDHCI_TIMING_MMC_HS400 4
#define SDHCI_TIMING_SD_ID 5
#define SDHCI_TIMING_SD_DS12 6
#define SDHCI_TIMING_SD_HS25 7
#define SDHCI_TIMING_UHS_SDR12 8
#define SDHCI_TIMING_UHS_SDR25 9
#define SDHCI_TIMING_UHS_SDR50 10
#define SDHCI_TIMING_UHS_SDR104 11
#define SDHCI_TIMING_UHS_SDR82 12 // SDR104 with a 163.2MHz -> 81.6MHz clock.
#define SDHCI_TIMING_UHS_DDR50 13
#define SDHCI_TIMING_MMC_DDR52 14
#define SDHCI_CAN_64BIT 0x10000000
/*! SDMMC Low power features. */
#define SDMMC_AUTO_CAL_DISABLE 0
#define SDMMC_AUTO_CAL_ENABLE 1
/*! Helper for SWITCH command argument. */
#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8))
@ -78,8 +213,8 @@ typedef struct _sdmmc_t
u32 id;
u32 divisor;
u32 clock_stopped;
int no_sd;
int sd_clock_enabled;
int auto_cal_enabled;
int card_clock_enabled;
int venclkctl_set;
u32 venclkctl_tap;
u32 expected_rsp_type;
@ -108,19 +243,20 @@ typedef struct _sdmmc_req_t
int is_auto_cmd12;
} sdmmc_req_t;
int sdmmc_get_voltage(sdmmc_t *sdmmc);
u32 sdmmc_get_bus_width(sdmmc_t *sdmmc);
int sdmmc_get_io_power(sdmmc_t *sdmmc);
u32 sdmmc_get_bus_width(sdmmc_t *sdmmc);
void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width);
void sdmmc_get_venclkctl(sdmmc_t *sdmmc);
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type);
void sdmmc_sd_clock_ctrl(sdmmc_t *sdmmc, int no_sd);
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type);
int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd);
int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp);
int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int no_sd);
void sdmmc_set_tap_value(sdmmc_t *sdmmc);
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type);
void sdmmc_card_clock_ctrl(sdmmc_t *sdmmc, int auto_cal_enable);
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type);
int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd);
int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp);
bool sdmmc_get_sd_inserted();
int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int auto_cal_enable);
void sdmmc_end(sdmmc_t *sdmmc);
void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy);
int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out);
int sdmmc_enable_low_voltage(sdmmc_t *sdmmc);
int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out);
int sdmmc_enable_low_voltage(sdmmc_t *sdmmc);
#endif

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -19,49 +20,14 @@
#include "../utils/types.h"
#define TEGRA_MMC_PWRCTL_SD_BUS_POWER 0x1
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 0xA
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0 0xC
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3 0xE
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK 0xF1
#define TEGRA_MMC_HOSTCTL_1BIT 0x00
#define TEGRA_MMC_HOSTCTL_4BIT 0x02
#define TEGRA_MMC_HOSTCTL_8BIT 0x20
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE 0x1
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE 0x2
#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE 0x4
#define TEGRA_MMC_CLKCON_CLKGEN_SELECT 0x20
#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL 0x1
#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE 0x2
#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE 0x4
#define TEGRA_MMC_TRNMOD_DMA_ENABLE 0x1
#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE 0x2
#define TEGRA_MMC_TRNMOD_AUTO_CMD12 0x4
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE 0x0
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ 0x10
#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT 0x20
#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK 0x8
#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK 0x10
#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER 0x20
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK 0x3
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE 0x0
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 0x1
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 0x2
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY 0x3
#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE 0x1
#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE 0x2
#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT 0x8
#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT 0x8000
#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT 0x10000
#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY 0x20
#define TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW 0x20000
#define TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE 0x80000000
#define TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE 0x80000000
#define TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD 0x80000000
#define TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK 0xFFFFFFF0
#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE 0x20000000
#define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START 0x80000000
#define TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE 0x80000000
typedef struct _t210_sdmmc_t
{
@ -77,56 +43,66 @@ typedef struct _t210_sdmmc_t
vu32 rspreg3;
vu32 bdata;
vu32 prnsts;
vu8 hostctl;
vu8 pwrcon;
vu8 blkgap;
vu8 wakcon;
vu8 hostctl;
vu8 pwrcon;
vu8 blkgap;
vu8 wakcon;
vu16 clkcon;
vu8 timeoutcon;
vu8 swrst;
vu8 timeoutcon;
vu8 swrst;
vu16 norintsts;
vu16 errintsts;
vu16 norintstsen;
vu16 errintstsen;
vu16 norintsigen;
vu16 errintsigen;
vu16 norintstsen; // Enable irq status.
vu16 errintstsen; // Enable irq status.
vu16 norintsigen; // Enable irq signal to LIC/GIC.
vu16 errintsigen; // Enable irq signal to LIC/GIC.
vu16 acmd12errsts;
vu16 hostctl2;
vu32 capareg;
vu32 capareg_1;
vu32 maxcurr;
vu8 res3[4];
vu8 rsvd0[4]; // 4C-4F reserved for more max current.
vu16 setacmd12err;
vu16 setinterr;
vu8 admaerr;
vu8 res4[3];
vu8 admaerr;
vu8 rsvd1[3]; // 55-57 reserved.
vu32 admaaddr;
vu32 admaaddr_hi;
vu8 res5[156];
vu16 slotintstatus;
vu8 rsvd2[156]; // 60-FB reserved.
vu16 slotintsts;
vu16 hcver;
vu32 venclkctl;
vu32 venspictl;
vu32 venspiintsts;
vu32 venceatactl;
vu32 vensysswctl;
vu32 venerrintsts;
vu32 vencapover;
vu32 venbootctl;
vu32 venbootacktout;
vu32 venbootdattout;
vu32 vendebouncecnt;
vu32 venmiscctl;
vu32 res6[34];
vu32 maxcurrover;
vu32 maxcurrover_hi;
vu32 unk0[32]; // 0x12C
vu32 veniotrimctl;
vu32 vendllcal;
vu8 res7[8];
vu32 dllcfgstatus;
vu32 vendllcalcfg;
vu32 vendllctl0;
vu32 vendllctl1;
vu32 vendllcalcfgsts;
vu32 ventunctl0;
vu32 field_1C4;
vu8 field_1C8[24];
vu32 ventunctl1;
vu32 ventunsts0;
vu32 ventunsts1;
vu32 venclkgatehystcnt;
vu32 venpresetval0;
vu32 venpresetval1;
vu32 venpresetval2;
vu32 sdmemcmppadctl;
vu32 autocalcfg;
vu32 autocalintval;
vu32 autocalsts;
vu32 iospare;
vu32 mcciffifoctl;
vu32 timeoutwcoal;
} t210_sdmmc_t;
#endif