1
0
Fork 0
mirror of https://github.com/Atmosphere-NX/Atmosphere.git synced 2024-11-22 11:56:40 +00:00

Fusee: Deployed new SDMMC driver in fusee-secondary. All stages boot now.

Fusee: Fixed wrong argument in se.c function.
Fusee: Improved timers.
This commit is contained in:
hexkyz 2018-07-19 21:07:53 +01:00
parent 49ba91a8f3
commit 3db9ce32fa
44 changed files with 5247 additions and 4802 deletions

View file

@ -4,7 +4,6 @@
#include "gpio.h"
#include "utils.h"
#include "lib/printk.h"
/**
* Returns a GPIO bank object that corresponds to the given GPIO pin,

View file

@ -4,6 +4,7 @@
#include "hwinit.h"
#include "fuse.h"
#include "se.h"
#include "timers.h"
#include "fs_utils.h"
#include "stage2.h"
#include "chainloader.h"
@ -122,14 +123,7 @@ int main(void) {
/* Say hello. */
printk("Welcome to Atmosph\xe8re Fus\xe9" "e!\n");
printk("Using color linear framebuffer at 0x%p!\n", g_framebuffer);
#ifndef I_KNOW_WHAT_I_AM_DOING
#error "Fusee is a work-in-progress bootloader, and is not ready for usage yet. If you want to play with it anyway, please #define I_KNOW_WHAT_I_AM_DOING -- and recognize that we will be unable to provide support until it is ready for general usage :)"
printk("Warning: Fus\xe9" "e is not yet completed, and not ready for general testing!\n");
fatal_error("Please do not seek support for it until it is done.\n");
#endif
/* Load the BCT0 configuration ini off of the SD. */
bct0 = load_config();
@ -142,10 +136,12 @@ int main(void) {
stage2_args = (stage2_args_t *)(g_chainloader_arg_data + strlen(stage2_path) + 1); /* May be unaligned. */
memcpy(&stage2_args->version, &stage2_version, 4);
stage2_args->display_initialized = false;
memcpy(&stage2_args->sd_sdmmc, &g_sd_sdmmc, sizeof(g_sd_sdmmc));
strcpy(stage2_args->bct0, bct0);
g_chainloader_argc = 2;
/* Wait a while. */
mdelay(1000);
/* Deinitialize the display, console, etc. */
cleanup_env();

View file

@ -189,7 +189,7 @@ static int sdmmc_device_rw(sdmmc_device_t *device, uint32_t sector, uint32_t num
sdmmc_device_send_status(device);
/* Wait for a while. */
udelay(100000);
mdelay(100);
}
else
break;
@ -504,8 +504,8 @@ static int sdmmc_sd_send_op_cond(sdmmc_device_t *device, bool is_sd_ver2, bool i
/* Keep checking if timeout expired. */
is_timeout = (get_time_since(timebase) > 2000000);
/* Delay for an appropriate period. */
udelay(10000);
/* Delay for a minimum of 10 milliseconds. */
mdelay(10);
}
return 0;
@ -1161,8 +1161,8 @@ static int sdmmc_mmc_send_op_cond(sdmmc_device_t *device, SdmmcBusVoltage bus_vo
/* Keep checking if timeout expired. */
is_timeout = (get_time_since(timebase) > 2000000);
/* Delay for an appropriate period. */
udelay(10000);
/* Delay for a minimum of 10 milliseconds. */
mdelay(10);
}
return 0;
@ -1357,11 +1357,23 @@ static int sdmmc_mmc_select_bkops(sdmmc_device_t *device)
return sdmmc_device_send_status(device);
}
int sdmmc_mmc_select_partition(sdmmc_device_t *device, SdmmcPartitionNum partition)
{
uint32_t arg = (((MMC_SWITCH_MODE_WRITE_BYTE) << 24) | ((EXT_CSD_PART_CONFIG) << 16) | ((partition) << 8));
/* Try to change the active partition. */
if (!sdmmc_mmc_switch(device, arg))
return 0;
/* Peek the current status. */
return sdmmc_device_send_status(device);
}
int sdmmc_device_mmc_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth bus_width, SdmmcBusSpeed bus_speed)
{
uint32_t cid[4] = {0};
uint32_t csd[4] = {0};
uint8_t ext_csd[512] = {0};
uint8_t *ext_csd = (uint8_t *)SDMMC_BOUNCE_BUFFER_ADDRESS; // TODO: Better way to do this.
/* Initialize our device's struct. */
memset(device, 0, sizeof(sdmmc_device_t));
@ -1376,6 +1388,9 @@ int sdmmc_device_mmc_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth
/* Bind the underlying driver. */
device->sdmmc = sdmmc;
/* Set RCA. */
device->rca = 0x01;
sdmmc_info(sdmmc, "SDMMC driver was successfully initialized for eMMC!");
/* Apply at least 74 clock cycles. eMMC should be ready afterwards. */
@ -1408,14 +1423,14 @@ int sdmmc_device_mmc_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth
sdmmc_info(sdmmc, "Got CID from eMMC!");
/* Get the eMMC's RCA. */
/* Set the eMMC's RCA. */
if (!sdmmc_mmc_set_relative_addr(device))
{
sdmmc_error(sdmmc, "Failed to get RCA!");
sdmmc_error(sdmmc, "Failed to set RCA!");
return 0;
}
sdmmc_info(sdmmc, "Got RCA (0x%08x) from eMMC!", device->rca);
sdmmc_info(sdmmc, "RCA is now set in eMMC!");
/* Get the eMMC card's CSD. */
if (!sdmmc_device_send_csd(device, csd))
@ -1484,7 +1499,7 @@ int sdmmc_device_mmc_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth
/* Decode and save the CID. */
sdmmc_mmc_decode_cid(device, cid);
/* TODO: Handle automatic BKOPS properly. Leave it disabled for now. */
if (false && device->ext_csd.bkops && !(device->ext_csd.auto_bkops_en & EXT_CSD_AUTO_BKOPS_MASK))
{
@ -1507,4 +1522,4 @@ int sdmmc_device_mmc_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth
sdmmc_adjust_sd_clock(sdmmc);
return 1;
}
}

View file

@ -156,5 +156,6 @@ int sdmmc_device_mmc_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth
int sdmmc_device_read(sdmmc_device_t *device, uint32_t sector, uint32_t num_sectors, void *data);
int sdmmc_device_write(sdmmc_device_t *device, uint32_t sector, uint32_t num_sectors, void *data);
int sdmmc_device_finish(sdmmc_device_t *device);
int sdmmc_mmc_select_partition(sdmmc_device_t *device, SdmmcPartitionNum partition);
#endif

View file

@ -14,8 +14,6 @@
#include "../lib/driver_utils.h"
#include "../hwinit/max7762x.h"
#define SDMMC_BOUNCE_BUFFER_ADDRESS 0x90000000
static SdmmcLogLevel g_sdmmc_log_level = SDMMC_LOG_NONE;
void sdmmc_set_log_level(SdmmcLogLevel log_level)
@ -116,7 +114,7 @@ void sdmmc_dump_regs(sdmmc_t *sdmmc)
sdmmc_debug(sdmmc, "max_current: 0x%08" PRIX32, sdmmc->regs->max_current);
sdmmc_debug(sdmmc, "set_acmd12_error: 0x%04" PRIX16, sdmmc->regs->set_acmd12_error);
sdmmc_debug(sdmmc, "set_int_error: 0x%04" PRIX16, sdmmc->regs->set_int_error);
sdmmc_debug(sdmmc, "adma_error: 0x%02" PRIX16, sdmmc->regs->adma_error);
sdmmc_debug(sdmmc, "adma_error: 0x%02" PRIX8, sdmmc->regs->adma_error);
sdmmc_debug(sdmmc, "adma_address: 0x%08" PRIX32, sdmmc->regs->adma_address);
sdmmc_debug(sdmmc, "upper_adma_address: 0x%08" PRIX32, sdmmc->regs->upper_adma_address);
sdmmc_debug(sdmmc, "preset_for_init: 0x%04" PRIX16, sdmmc->regs->preset_for_init);
@ -700,10 +698,13 @@ static int sdmmc_int_clk_enable(sdmmc_t *sdmmc)
/* Change to ADMA if requested. */
if (sdmmc->use_adma && (sdmmc->regs->capabilities & SDHCI_CAN_DO_ADMA2)) {
// TODO: Setting the ADMA flags breaks ADMA...
/*
if (sdmmc->regs->capabilities & SDHCI_CAN_64BIT)
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA64;
else
sdmmc->regs->host_control |= SDHCI_CTRL_ADMA32;
*/
}
/* Set the timeout to be the maximum value. */
@ -1092,7 +1093,7 @@ static int sdmmc_init_controller(sdmmc_t *sdmmc, SdmmcControllerNum controller)
sdmmc->is_clk_running = false;
sdmmc->is_sd_clk_enabled = false;
sdmmc->is_tuning_tap_val_set = false;
sdmmc->use_adma = false;
sdmmc->use_adma = true;
sdmmc->dma_bounce_buf = (uint8_t*)SDMMC_BOUNCE_BUFFER_ADDRESS;
sdmmc->tap_val = 0;
sdmmc->internal_divider = 0;
@ -1201,13 +1202,23 @@ void sdmmc_finish(sdmmc_t *sdmmc)
/* Disable the SD clock. */
sdmmc_disable_sd_clock(sdmmc);
/* Disable SD power. */
/* Disable SDMMC power. */
sdmmc_select_voltage(sdmmc, SDMMC_VOLTAGE_NONE);
/* Disable the SD card power. */
if (sdmmc->controller == SDMMC_1)
{
/* Disable GPIO output. */
gpio_configure_direction(GPIO_MICROSD_SUPPLY_ENABLE, GPIO_DIRECTION_INPUT);
/* Power cycle for 100ms without power. */
mdelay(100);
}
/* Force a register read to refresh the clock control value. */
sdmmc_get_sd_clock_control(sdmmc);
/* Stop the SD clock. */
/* Stop the SDMMC clock. */
sdmmc_clk_stop(sdmmc->controller);
/* Clock is no longer running by now. */
@ -1307,7 +1318,8 @@ static int sdmmc_wait_busy(sdmmc_t *sdmmc)
static void sdmmc_intr_enable(sdmmc_t *sdmmc)
{
/* Set all error bits and enable the relevant interrupts. */
sdmmc->regs->int_enable |= (0x017F0000 | (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT));
sdmmc->regs->int_enable |= 0x017F0000;
sdmmc->regs->int_enable |= (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT);
/* Refresh status. */
sdmmc->regs->int_status = sdmmc->regs->int_status;
@ -1315,11 +1327,15 @@ static void sdmmc_intr_enable(sdmmc_t *sdmmc)
static void sdmmc_intr_disable(sdmmc_t *sdmmc)
{
/* Clear the interrupt bits. */
sdmmc->regs->int_enable &= ~(0x017F0000 | (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT));
/* Clear all error bits and the interrupts. */
sdmmc->regs->int_enable &= ~(0x017F0000);
sdmmc->regs->int_enable &= ~(TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE | TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE | TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT);
/* Refresh status. */
sdmmc->regs->int_status = sdmmc->regs->int_status;
}
static bool sdmmc_intr_check_status(sdmmc_t *sdmmc, u16 status_mask)
static bool sdmmc_intr_check_status(sdmmc_t *sdmmc, uint16_t status_mask)
{
bool is_masked = (sdmmc->regs->int_status & status_mask);
@ -1353,8 +1369,8 @@ static int sdmmc_dma_init(sdmmc_t *sdmmc, sdmmc_request_t *req)
if (blkcnt >= 0xFFFF)
blkcnt = 0xFFFF;
/* Point to our bounce buffer. */
uint32_t dma_base_addr = (uint32_t)sdmmc->dma_bounce_buf;
/* Use our bounce buffer for SDMA or the request data buffer for ADMA. */
uint32_t dma_base_addr = sdmmc->use_adma ? (uint32_t)req->data : (uint32_t)sdmmc->dma_bounce_buf;
/* DMA buffer address must be aligned to 4 bytes. */
if ((4 - (dma_base_addr & 0x03)) & 0x03)
@ -1408,7 +1424,7 @@ static int sdmmc_dma_init(sdmmc_t *sdmmc, sdmmc_request_t *req)
static int sdmmc_dma_update(sdmmc_t *sdmmc)
{
u16 blkcnt = 0;
uint16_t blkcnt = 0;
/* Loop until all blocks have been consumed. */
do
@ -1464,7 +1480,7 @@ static int sdmmc_dma_update(sdmmc_t *sdmmc)
static void sdmmc_set_cmd_flags(sdmmc_t *sdmmc, sdmmc_command_t *cmd, bool is_dma)
{
u16 cmd_reg_flags = 0;
uint16_t cmd_reg_flags = 0;
/* Select length flags based on response type. */
if (!(cmd->flags & SDMMC_RSP_PRESENT))
@ -1629,8 +1645,8 @@ int sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_command_t *cmd, sdmmc_request_t *req, u
return 0;
}
/* If this is a write operation, copy the data into our bounce buffer. */
if (!req->is_read)
/* If this is a SDMA write operation, copy the data into our bounce buffer. */
if (!sdmmc->use_adma && !req->is_read)
memcpy((void *)sdmmc->dma_bounce_buf, (void *)req->data, req->blksz * req->num_blocks);
}
@ -1659,8 +1675,8 @@ int sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_command_t *cmd, sdmmc_request_t *req, u
return 0;
}
/* If this is a read operation, copy the data from our bounce buffer. */
if (req->is_read)
/* If this is a SDMA read operation, copy the data from our bounce buffer. */
if (!sdmmc->use_adma && req->is_read)
{
uint32_t dma_data_size = (sdmmc->regs->dma_address - (uint32_t)sdmmc->dma_bounce_buf);
memcpy((void *)req->data, (void *)sdmmc->dma_bounce_buf, dma_data_size);
@ -1853,7 +1869,7 @@ static int sdmmc_send_tuning(sdmmc_t *sdmmc, uint32_t opcode)
void sdmmc_set_tuning_tap_val(sdmmc_t *sdmmc)
{
sdmmc->tap_val = ((sdmmc->regs->vendor_clock_cntrl & 0xFF0000) >> 16);
sdmmc->tap_val = (sdmmc->regs->vendor_clock_cntrl >> 16);
sdmmc->is_tuning_tap_val_set = true;
}

View file

@ -3,6 +3,9 @@
#include "sdmmc_tegra.h"
/* Bounce buffer */
#define SDMMC_BOUNCE_BUFFER_ADDRESS 0x90000000
/* Present state */
#define SDHCI_CMD_INHIBIT 0x00000001
#define SDHCI_DATA_INHIBIT 0x00000002
@ -177,6 +180,14 @@ typedef enum {
SDMMC_4 = 3
} SdmmcControllerNum;
typedef enum {
SDMMC_PARTITION_INVALID = -1,
SDMMC_PARTITION_USER = 0,
SDMMC_PARTITION_BOOT0 = 1,
SDMMC_PARTITION_BOOT1 = 2,
SDMMC_PARTITION_RPMB = 3
} SdmmcPartitionNum;
typedef enum {
SDMMC_VOLTAGE_NONE = 0,
SDMMC_VOLTAGE_1V8 = 1,

View file

@ -21,7 +21,6 @@ typedef struct {
typedef struct {
uint32_t version;
sdmmc_t sd_sdmmc;
bool display_initialized;
char bct0[BCTO_MAX_SIZE];
} stage2_args_t;

View file

@ -7,6 +7,11 @@
#define MAKE_TIMERS_REG(n) MAKE_REG32(TIMERS_BASE + n)
#define TIMERUS_CNTR_1US_0 MAKE_REG32(TIMERS_BASE + 0x10)
#define RTC_BASE 0x7000E000
#define RTC_SECONDS MAKE_REG32(RTC_BASE + 0x08)
#define RTC_SHADOW_SECONDS MAKE_REG32(RTC_BASE + 0x0C)
#define RTC_MILLI_SECONDS MAKE_REG32(RTC_BASE + 0x10)
typedef struct {
uint32_t CONFIG;
uint32_t STATUS;
@ -20,23 +25,46 @@ typedef struct {
void wait(uint32_t microseconds);
static inline uint32_t get_time(void) {
static inline uint32_t get_time_s(void) {
return RTC_SECONDS;
}
static inline uint32_t get_time_ms(void) {
return (RTC_MILLI_SECONDS | (RTC_SHADOW_SECONDS << 10));
}
static inline uint32_t get_time_us(void) {
return TIMERUS_CNTR_1US_0;
}
/**
* Returns the time in microseconds.
*/
static inline uint32_t get_time(void) {
return get_time_us();
}
/**
* Returns the number of microseconds that have passed since a given get_time().
*/
static inline uint32_t get_time_since(uint32_t base) {
return get_time() - base;
return get_time_us() - base;
}
/**
* Delays for a given number of microseconds.
*/
static inline void udelay(unsigned usecs) {
uint32_t start = get_time();
while (get_time() - start < usecs);
static inline void udelay(uint32_t usecs) {
uint32_t start = get_time_us();
while (get_time_us() - start < usecs);
}
/**
* Delays for a given number of milliseconds.
*/
static inline void mdelay(uint32_t msecs) {
uint32_t start = get_time_ms();
while (get_time_ms() - start < msecs);
}
__attribute__ ((noreturn)) void watchdog_reboot(void);

View file

@ -21,7 +21,7 @@ include $(DEVKITARM)/base_rules
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := src src/lib src/lib/fatfs src/display src/hwinit
SOURCES := src src/sdmmc src/hwinit src/lib src/lib/fatfs src/display
DATA := data
INCLUDES := include

View file

@ -1,15 +1,5 @@
#ifndef __APB_MISC_H__
#define __APB_MISC_H__
/* FIXME: clean up */
#define MISC_BASE (0x70000000UL)
#define PINMUX_BASE (MISC_BASE + 0x3000)
#define PINMUX_AUX_GPIO_PZ1_0 (*(volatile uint32_t *)(PINMUX_BASE + 0x280))
#define APB_MISC_GP_VGPIO_GPIO_MUX_SEL_0 MAKE_REG32(MISC_BASE + 0xb74)
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xa98)
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL_0 MAKE_REG32(MISC_BASE + 0xab4)
#ifndef FUSEE_APB_MISC_H
#define FUSEE_APB_MISC_H
#define SDMMC1_PAD_CAL_DRVUP_SHIFT (20)
#define SDMMC1_PAD_CAL_DRVDN_SHIFT (12)
@ -21,4 +11,44 @@
#define CFG2TMC_EMMC4_PAD_DRVUP_COMP_MASK (0x3Fu << CFG2TMC_EMMC4_PAD_DRVUP_COMP_SHIFT)
#define CFG2TMC_EMMC4_PAD_DRVDN_COMP_MASK (0x3Fu << CFG2TMC_EMMC4_PAD_DRVDN_COMP_SHIFT)
#define PADCTL_SDMMC1_DEEP_LOOPBACK (1 << 0)
#define PADCTL_SDMMC3_DEEP_LOOPBACK (1 << 0)
#define PADCTL_SDMMC2_ENABLE_DATA_IN (0xFF << 8)
#define PADCTL_SDMMC2_ENABLE_CLK_IN (0x3 << 4)
#define PADCTL_SDMMC2_DEEP_LOOPBACK (1 << 0)
#define PADCTL_SDMMC4_ENABLE_DATA_IN (0xFF << 8)
#define PADCTL_SDMMC4_ENABLE_CLK_IN (0x3 << 4)
#define PADCTL_SDMMC4_DEEP_LOOPBACK (1 << 0)
#define PADCTL_SDMMC1_CD_SOURCE (1 << 0)
#define PADCTL_SDMMC1_WP_SOURCE (1 << 1)
#define PADCTL_SDMMC3_CD_SOURCE (1 << 2)
#define PADCTL_SDMMC3_WP_SOURCE (1 << 3)
typedef struct {
uint32_t asdbgreg; /* 0x810 */
uint32_t reserved0[0x31];
uint32_t sdmmc1_clk_lpbk_control; /* 0x8D4 */
uint32_t sdmmc3_clk_lpbk_control; /* 0x8D8 */
uint32_t emmc2_pad_cfg_control; /* 0x8DC */
uint32_t emmc4_pad_cfg_control; /* 0x8E0 */
uint32_t _todo0[0x6E];
uint32_t sdmmc1_pad_cfgpadctrl; /* 0xA98 */
uint32_t emmc2_pad_cfgpadctrl; /* 0xA9C */
uint32_t emmc2_pad_drv_type_cfgpadctrl; /* 0xAA0 */
uint32_t emmc2_pad_pupd_cfgpadctrl; /* 0xAA4 */
uint32_t _todo1[0x03];
uint32_t sdmmc3_pad_cfgpadctrl; /* 0xAB0 */
uint32_t emmc4_pad_cfgpadctrl; /* 0xAB4 */
uint32_t emmc4_pad_drv_type_cfgpadctrl; /* 0xAB8 */
uint32_t emmc4_pad_pupd_cfgpadctrl; /* 0xABC */
uint32_t _todo2[0x2E];
uint32_t vgpio_gpio_mux_sel; /* 0xB74 */
uint32_t qspi_sck_lpbk_control; /* 0xB78 */
} tegra_padctl_t;
static inline volatile tegra_padctl_t *padctl_get_regs(void)
{
return (volatile tegra_padctl_t *)0x70000810;
}
#endif

View file

@ -1,95 +1,68 @@
#ifndef FUSEE_CAR_H
#define FUSEE_CAR_H
#ifndef __FUSEE_CLOCK_H__
#define __FUSEE_CLOCK_H__
#define CLK_SOURCE_SDMMC1 20
#define CLK_SOURCE_SDMMC2 21
#define CLK_SOURCE_SDMMC3 47
#define CLK_SOURCE_SDMMC4 25
#define CLK_SOURCE_SDMMC_LEGACY 0
#include "utils.h"
#define CLK_L_SDMMC1 (1 << 14)
#define CLK_L_SDMMC2 (1 << 9)
#define CLK_U_SDMMC3 (1 << 5)
#define CLK_L_SDMMC4 (1 << 15)
/**
* Struct definition yanked from u-boot.
*/
#define TEGRA_CLK_PLLS 6 /* Number of normal PLLs */
#define TEGRA_CLK_SIMPLE_PLLS 3 /* Number of simple PLLs */
#define TEGRA_CLK_SOURCES 64 /* Number of ppl clock sources L/H/U */
#define TEGRA_CLK_SOURCES_VW 32 /* Number of ppl clock sources V/W */
#define TEGRA_CLK_SOURCES_X 32 /* Number of ppl clock sources X */
#define TEGRA_CLK_SOURCES_Y 18 /* Number of ppl clock sources Y */
#define CLK_SOURCE_MASK (0b111 << 29)
#define CLK_SOURCE_FIRST (0b000 << 29)
#define CLK_DIVIDER_MASK (0xff << 0)
#define CLK_DIVIDER_UNITY (0x00 << 0)
#define CAR_CONTROL_SDMMC1 (1 << 14)
#define CAR_CONTROL_SDMMC4 (1 << 15)
#define CAR_CONTROL_SDMMC_LEGACY (1 << 1)
/* PLL registers - there are several PLLs in the clock controller */
struct clk_pll {
typedef struct {
uint32_t pll_base; /* the control register */
/* pll_out[0] is output A control, pll_out[1] is output B control */
uint32_t pll_out[2];
uint32_t pll_misc; /* other misc things */
};
} clk_pll_t;
/* PLL registers - there are several PLLs in the clock controller */
struct clk_pll_simple {
typedef struct {
uint32_t pll_base; /* the control register */
uint32_t pll_misc; /* other misc things */
};
} clk_pll_simple_t;
struct clk_pllm {
typedef struct {
uint32_t pllm_base; /* the control register */
uint32_t pllm_out; /* output control */
uint32_t pllm_misc1; /* misc1 */
uint32_t pllm_misc2; /* misc2 */
};
/*
* Most PLLs use the clk_pll structure, but some have a simpler two-member
* structure for which we use clk_pll_simple. The reason for this non-
* othogonal setup is not stated.
*/
enum {
TEGRA_CLK_PLLS = 6, /* Number of normal PLLs */
TEGRA_CLK_SIMPLE_PLLS = 3, /* Number of simple PLLs */
TEGRA_CLK_SOURCES = 64, /* Number of ppl clock sources L/H/U */
TEGRA_CLK_SOURCES_VW = 32, /* Number of ppl clock sources V/W */
TEGRA_CLK_SOURCES_X = 32, /* Number of ppl clock sources X */
TEGRA_CLK_SOURCES_Y = 18, /* Number of ppl clock sources Y */
};
/*
* Masks for TEGRA_CLK_SOURCE elements.
*/
enum {
CLK_SOURCE_MASK = (0b111 << 29),
CLK_SOURCE_SDMMC1_PLLP_OUT0 = (0b000 << 29), /* Fixed 408 MHz */
CLK_SOURCE_SDMMC4_PLLP_OUT0 = (0b000 << 29), /* Fixed 408 MHz */
CLK_SOURCE_SDMMC4_PLLC4_OUT2_LJ = (0b001 << 29), /* 199.68 MHz */
CLK_SOURCE_SDMMC_LEGACY_PLLP_OUT0 = (0b100 << 29), /* Fixed 408 MHz */
CLK_DIVIDER_MASK = (0xff << 0),
CLK_DIVIDER_UNITY = (0x00 << 0),
};
/**
* Reset bits for relevant registers.
*/
enum {
CAR_CONTROL_SDMMC1 = (1 << 14),
CAR_CONTROL_SDMMC4 = (1 << 15),
CAR_CONTROL_SDMMC_LEGACY = (1 << 1),
};
enum {
CLK_SOURCE_SDMMC1 = 20,
CLK_SOURCE_SDMMC4 = 25, /* 0x54 into the the main source block */
CLK_SOURCE_SDMMC_LEGACY = 0, /* first in block Y */
};
} clk_pllm_t;
/* Clock/Reset Controller (CLK_RST_CONTROLLER_) regs */
struct tegra_car {
typedef struct {
uint32_t rst_src; /* _RST_SOURCE_0,0x00 */
uint32_t rst_dev_l;
uint32_t rst_dev_h;
uint32_t rst_dev_u;
uint32_t clk_out_dev_l;
uint32_t clk_out_dev_h;
uint32_t clk_out_dev_u;
uint32_t clk_out_enb_l;
uint32_t clk_out_enb_h;
uint32_t clk_out_enb_u;
uint32_t reserved0; /* reserved_0, 0x1C */
uint32_t reserved0; /* reserved_0, 0x1C */
uint32_t cclk_brst_pol; /* _CCLK_BURST_POLICY_0, 0x20 */
uint32_t super_cclk_div; /* _SUPER_CCLK_DIVIDER_0,0x24 */
uint32_t sclk_brst_pol; /* _SCLK_BURST_POLICY_0, 0x28 */
@ -97,21 +70,21 @@ struct tegra_car {
uint32_t clk_sys_rate; /* _CLK_SYSTEM_RATE_0, 0x30 */
uint32_t prog_dly_clk; /* _PROG_DLY_CLK_0, 0x34 */
uint32_t aud_sync_clk_rate; /* _AUDIO_SYNC_CLK_RATE_0,0x38 */
uint32_t reserved1; /* reserved_1, 0x3C */
uint32_t reserved1; /* reserved_1, 0x3C */
uint32_t cop_clk_skip_plcy; /* _COP_CLK_SKIP_POLICY_0,0x40 */
uint32_t clk_mask_arm; /* _CLK_MASK_ARM_0, 0x44 */
uint32_t misc_clk_enb; /* _MISC_CLK_ENB_0, 0x48 */
uint32_t clk_cpu_cmplx; /* _CLK_CPU_CMPLX_0, 0x4C */
uint32_t osc_ctrl; /* _OSC_CTRL_0, 0x50 */
uint32_t pll_lfsr; /* _PLL_LFSR_0, 0x54 */
uint32_t osc_ctrl; /* _OSC_CTRL_0, 0x50 */
uint32_t pll_lfsr; /* _PLL_LFSR_0, 0x54 */
uint32_t osc_freq_det; /* _OSC_FREQ_DET_0, 0x58 */
uint32_t osc_freq_det_stat; /* _OSC_FREQ_DET_STATUS_0,0x5C */
uint32_t reserved2[8]; /* reserved_2[8], 0x60-7C */
struct clk_pll pll[TEGRA_CLK_PLLS]; /* PLLs from 0x80 to 0xdc */
clk_pll_t pll[TEGRA_CLK_PLLS]; /* PLLs from 0x80 to 0xdc */
/* PLLs from 0xe0 to 0xf4 */
struct clk_pll_simple pll_simple[TEGRA_CLK_SIMPLE_PLLS];
clk_pll_simple_t pll_simple[TEGRA_CLK_SIMPLE_PLLS];
uint32_t reserved10; /* _reserved_10, 0xF8 */
uint32_t reserved11; /* _reserved_11, 0xFC */
@ -171,11 +144,11 @@ struct tegra_car {
uint32_t reserved32[2]; /* _reserved_32, 0x350,0x354 */
uint32_t rst_dev_v; /* _RST_DEVICES_V/W_0 */
uint32_t rst_dev_w; /* _RST_DEVICES_V/W_0 */
uint32_t rst_dev_v; /* _RST_DEVICES_V/W_0 */
uint32_t rst_dev_w; /* _RST_DEVICES_V/W_0 */
uint32_t clk_out_enb_v; /* _CLK_OUT_ENB_V/W_0 */
uint32_t clk_out_enb_w; /* _CLK_OUT_ENB_V/W_0 */
uint32_t clk_out_enb_v; /* _CLK_OUT_ENB_V/W_0 */
uint32_t clk_out_enb_w; /* _CLK_OUT_ENB_V/W_0 */
uint32_t cclkg_brst_pol; /* _CCLKG_BURST_POLICY_0, 0x368 */
uint32_t super_cclkg_div; /* _SUPER_CCLKG_DIVIDER_0, 0x36C */
uint32_t cclklp_brst_pol; /* _CCLKLP_BURST_POLICY_0, 0x370 */
@ -186,8 +159,8 @@ struct tegra_car {
uint32_t cpu_softrst_ctrl1; /* _CPU_SOFTRST_CTRL1_0, 0x384 */
uint32_t cpu_softrst_ctrl2; /* _CPU_SOFTRST_CTRL2_0, 0x388 */
uint32_t reserved33[9]; /* _reserved_33, 0x38c-3ac */
uint32_t clk_src_v; /* 0x3B0-0x42C */
uint32_t clk_src_w; /* 0x3B0-0x42C */
uint32_t clk_src_v; /* 0x3B0-0x42C */
uint32_t clk_src_w; /* 0x3B0-0x42C */
/* _RST_DEV_V/W_SET_0 0x430 ~ 0x43c */
uint32_t rst_dev_v_set;
@ -210,18 +183,18 @@ struct tegra_car {
uint32_t clk_cpug_cmplx_clr; /* _CLK_CPUG_CMPLX_CLR_0, 0x464 */
uint32_t clk_cpulp_cmplx_set; /* _CLK_CPULP_CMPLX_SET_0, 0x468 */
uint32_t clk_cpulp_cmplx_clr; /* _CLK_CPULP_CMPLX_CLR_0, 0x46C */
uint32_t cpu_cmplx_status; /* _CPU_CMPLX_STATUS_0, 0x470 */
uint32_t reserved40[1]; /* _reserved_40, 0x474 */
uint32_t intstatus; /* __INTSTATUS_0, 0x478 */
uint32_t intmask; /* __INTMASK_0, 0x47C */
uint32_t utmip_pll_cfg0; /* _UTMIP_PLL_CFG0_0, 0x480 */
uint32_t utmip_pll_cfg1; /* _UTMIP_PLL_CFG1_0, 0x484 */
uint32_t utmip_pll_cfg2; /* _UTMIP_PLL_CFG2_0, 0x488 */
uint32_t cpu_cmplx_status; /* _CPU_CMPLX_STATUS_0, 0x470 */
uint32_t reserved40[1]; /* _reserved_40, 0x474 */
uint32_t intstatus; /* __INTSTATUS_0, 0x478 */
uint32_t intmask; /* __INTMASK_0, 0x47C */
uint32_t utmip_pll_cfg0; /* _UTMIP_PLL_CFG0_0, 0x480 */
uint32_t utmip_pll_cfg1; /* _UTMIP_PLL_CFG1_0, 0x484 */
uint32_t utmip_pll_cfg2; /* _UTMIP_PLL_CFG2_0, 0x488 */
uint32_t plle_aux; /* _PLLE_AUX_0, 0x48C */
uint32_t sata_pll_cfg0; /* _SATA_PLL_CFG0_0, 0x490 */
uint32_t sata_pll_cfg1; /* _SATA_PLL_CFG1_0, 0x494 */
uint32_t pcie_pll_cfg0; /* _PCIE_PLL_CFG0_0, 0x498 */
uint32_t plle_aux; /* _PLLE_AUX_0, 0x48C */
uint32_t sata_pll_cfg0; /* _SATA_PLL_CFG0_0, 0x490 */
uint32_t sata_pll_cfg1; /* _SATA_PLL_CFG1_0, 0x494 */
uint32_t pcie_pll_cfg0; /* _PCIE_PLL_CFG0_0, 0x498 */
uint32_t prog_audio_dly_clk; /* _PROG_AUDIO_DLY_CLK_0, 0x49C */
uint32_t audio_sync_clk_i2s0; /* _AUDIO_SYNC_CLK_I2S0_0, 0x4A0 */
@ -231,68 +204,65 @@ struct tegra_car {
uint32_t audio_sync_clk_i2s4; /* _AUDIO_SYNC_CLK_I2S4_0, 0x4B0 */
uint32_t audio_sync_clk_spdif; /* _AUDIO_SYNC_CLK_SPDIF_0, 0x4B4 */
uint32_t plld2_base; /* _PLLD2_BASE_0, 0x4B8 */
uint32_t plld2_misc; /* _PLLD2_MISC_0, 0x4BC */
uint32_t utmip_pll_cfg3; /* _UTMIP_PLL_CFG3_0, 0x4C0 */
uint32_t pllrefe_base; /* _PLLREFE_BASE_0, 0x4C4 */
uint32_t pllrefe_misc; /* _PLLREFE_MISC_0, 0x4C8 */
uint32_t plld2_base; /* _PLLD2_BASE_0, 0x4B8 */
uint32_t plld2_misc; /* _PLLD2_MISC_0, 0x4BC */
uint32_t utmip_pll_cfg3; /* _UTMIP_PLL_CFG3_0, 0x4C0 */
uint32_t pllrefe_base; /* _PLLREFE_BASE_0, 0x4C4 */
uint32_t pllrefe_misc; /* _PLLREFE_MISC_0, 0x4C8 */
uint32_t crs_reserved_50[7]; /* _reserved_50, 0x4CC-0x4E4 */
uint32_t pllc2_base; /* _PLLC2_BASE_0, 0x4E8 */
uint32_t pllc2_misc0; /* _PLLC2_MISC_0_0, 0x4EC */
uint32_t pllc2_misc1; /* _PLLC2_MISC_1_0, 0x4F0 */
uint32_t pllc2_misc2; /* _PLLC2_MISC_2_0, 0x4F4 */
uint32_t pllc2_misc3; /* _PLLC2_MISC_3_0, 0x4F8 */
uint32_t pllc3_base; /* _PLLC3_BASE_0, 0x4FC */
uint32_t pllc3_misc0; /* _PLLC3_MISC_0_0, 0x500 */
uint32_t pllc3_misc1; /* _PLLC3_MISC_1_0, 0x504 */
uint32_t pllc3_misc2; /* _PLLC3_MISC_2_0, 0x508 */
uint32_t pllc3_misc3; /* _PLLC3_MISC_3_0, 0x50C */
uint32_t pllx_misc1; /* _PLLX_MISC_1_0, 0x510 */
uint32_t pllx_misc2; /* _PLLX_MISC_2_0, 0x514 */
uint32_t pllx_misc3; /* _PLLX_MISC_3_0, 0x518 */
uint32_t xusbio_pll_cfg0; /* _XUSBIO_PLL_CFG0_0, 0x51C */
uint32_t xusbio_pll_cfg1; /* _XUSBIO_PLL_CFG0_1, 0x520 */
uint32_t plle_aux1; /* _PLLE_AUX1_0, 0x524 */
uint32_t pllp_reshift; /* _PLLP_RESHIFT_0, 0x528 */
uint32_t pllc2_base; /* _PLLC2_BASE_0, 0x4E8 */
uint32_t pllc2_misc0; /* _PLLC2_MISC_0_0, 0x4EC */
uint32_t pllc2_misc1; /* _PLLC2_MISC_1_0, 0x4F0 */
uint32_t pllc2_misc2; /* _PLLC2_MISC_2_0, 0x4F4 */
uint32_t pllc2_misc3; /* _PLLC2_MISC_3_0, 0x4F8 */
uint32_t pllc3_base; /* _PLLC3_BASE_0, 0x4FC */
uint32_t pllc3_misc0; /* _PLLC3_MISC_0_0, 0x500 */
uint32_t pllc3_misc1; /* _PLLC3_MISC_1_0, 0x504 */
uint32_t pllc3_misc2; /* _PLLC3_MISC_2_0, 0x508 */
uint32_t pllc3_misc3; /* _PLLC3_MISC_3_0, 0x50C */
uint32_t pllx_misc1; /* _PLLX_MISC_1_0, 0x510 */
uint32_t pllx_misc2; /* _PLLX_MISC_2_0, 0x514 */
uint32_t pllx_misc3; /* _PLLX_MISC_3_0, 0x518 */
uint32_t xusbio_pll_cfg0; /* _XUSBIO_PLL_CFG0_0, 0x51C */
uint32_t xusbio_pll_cfg1; /* _XUSBIO_PLL_CFG0_1, 0x520 */
uint32_t plle_aux1; /* _PLLE_AUX1_0, 0x524 */
uint32_t pllp_reshift; /* _PLLP_RESHIFT_0, 0x528 */
uint32_t utmipll_hw_pwrdn_cfg0; /* _UTMIPLL_HW_PWRDN_CFG0_0, 0x52C */
uint32_t pllu_hw_pwrdn_cfg0; /* _PLLU_HW_PWRDN_CFG0_0, 0x530 */
uint32_t xusb_pll_cfg0; /* _XUSB_PLL_CFG0_0, 0x534 */
uint32_t reserved51[1]; /* _reserved_51, 0x538 */
uint32_t clk_cpu_misc; /* _CLK_CPU_MISC_0, 0x53C */
uint32_t clk_cpug_misc; /* _CLK_CPUG_MISC_0, 0x540 */
uint32_t clk_cpulp_misc; /* _CLK_CPULP_MISC_0, 0x544 */
uint32_t pllx_hw_ctrl_cfg; /* _PLLX_HW_CTRL_CFG_0, 0x548 */
uint32_t pllx_sw_ramp_cfg; /* _PLLX_SW_RAMP_CFG_0, 0x54C */
uint32_t xusb_pll_cfg0; /* _XUSB_PLL_CFG0_0, 0x534 */
uint32_t reserved51[1]; /* _reserved_51, 0x538 */
uint32_t clk_cpu_misc; /* _CLK_CPU_MISC_0, 0x53C */
uint32_t clk_cpug_misc; /* _CLK_CPUG_MISC_0, 0x540 */
uint32_t clk_cpulp_misc; /* _CLK_CPULP_MISC_0, 0x544 */
uint32_t pllx_hw_ctrl_cfg; /* _PLLX_HW_CTRL_CFG_0, 0x548 */
uint32_t pllx_sw_ramp_cfg; /* _PLLX_SW_RAMP_CFG_0, 0x54C */
uint32_t pllx_hw_ctrl_status; /* _PLLX_HW_CTRL_STATUS_0, 0x550 */
uint32_t reserved52[1]; /* _reserved_52, 0x554 */
uint32_t reserved52[1]; /* _reserved_52, 0x554 */
uint32_t super_gr3d_clk_div; /* _SUPER_GR3D_CLK_DIVIDER_0, 0x558 */
uint32_t spare_reg0; /* _SPARE_REG0_0, 0x55C */
uint32_t _rsv32[4]; /* 0x560-0x56c */
uint32_t plld2_ss_cfg; /* _PLLD2_SS_CFG 0x570 */
uint32_t _rsv32_1[7]; /* 0x574-58c */
struct clk_pll_simple plldp; /* _PLLDP_BASE, 0x590 _PLLDP_MISC */
uint32_t plldp_ss_cfg; /* _PLLDP_SS_CFG, 0x598 */
uint32_t spare_reg0; /* _SPARE_REG0_0, 0x55C */
uint32_t _rsv32[4]; /* 0x560-0x56c */
uint32_t plld2_ss_cfg; /* _PLLD2_SS_CFG 0x570 */
uint32_t _rsv32_1[7]; /* 0x574-58c */
clk_pll_simple_t plldp; /* _PLLDP_BASE, 0x590 _PLLDP_MISC */
uint32_t plldp_ss_cfg; /* _PLLDP_SS_CFG, 0x598 */
/* Tegra124+ - skip to 0x600 here for new CLK_SOURCE_ regs */
uint32_t _rsrv32_2[25]; /* _0x59C - 0x5FC */
uint32_t clk_src_x[TEGRA_CLK_SOURCES_X]; /* XUSB, etc, 0x600-0x67C */
uint32_t _rsrv32_2[25]; /* _0x59C - 0x5FC */
uint32_t clk_src_x[TEGRA_CLK_SOURCES_X]; /* XUSB, etc, 0x600-0x67C */
/* Tegra210 - skip to 0x694 here for new CLK_SOURCE_ regs */
uint32_t reserved61[5]; /* _reserved_61, 0x680 - 0x690 */
uint32_t reserved61[5]; /* _reserved_61, 0x680 - 0x690 */
/*
* NOTE: PLLA1 regs are in the middle of this Y region. Break this in
* two later if PLLA1 is needed, but for now this is cleaner.
*/
uint32_t clk_src_y[TEGRA_CLK_SOURCES_Y]; /* SPARE1, etc, 0x694-0x6D8 */
};
} tegra_car_t;
/**
* Utility function that grabs the Tegra CAR registers.
*/
static inline struct tegra_car *car_get_regs(void)
static inline volatile tegra_car_t *car_get_regs(void)
{
return (struct tegra_car *)0x60006000UL;
return (volatile tegra_car_t *)0x60006000;
}
#endif

View file

@ -1,7 +1,8 @@
#include <string.h>
#include "device_partition.h"
int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) {
int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors)
{
int rc;
if (!devpart->initialized) {
rc = devpart->initializer(devpart);
@ -28,16 +29,15 @@ int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t
}
}
int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) {
int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors)
{
int rc;
if (!devpart->initialized) {
rc = devpart->initializer(devpart);
if (rc != 0) {
return rc;
}
}
if (devpart->read_cipher != NULL && devpart->crypto_mode != DevicePartitionCryptoMode_None) {
for (uint64_t i = 0; i < num_sectors; i += devpart->crypto_work_buffer_num_sectors) {
uint64_t n = (i + devpart->crypto_work_buffer_num_sectors > num_sectors) ? (num_sectors - i) : devpart->crypto_work_buffer_num_sectors;

View file

@ -2,6 +2,7 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#include <sys/iosupport.h>
@ -104,7 +105,7 @@ int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool
fsdev_device_t *device = fsdev_find_device(name);
FRESULT rc;
char drname[40];
if (device != NULL) {
errno = EEXIST; /* Device already exists */
return -1;
@ -153,7 +154,7 @@ int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool
VolumeStr[device - g_fsdev_devices] = FKNAM;
return fsdev_convert_rc(NULL, rc);
}
device->setup = true;
device->registered = false;

View file

@ -1,8 +1,6 @@
#include <stdio.h>
#include <sys/stat.h>
#include "fs_utils.h"
#include "hwinit.h"
#include "sdmmc.h"
size_t get_file_size(const char *filename) {
struct stat st;

View file

@ -2,7 +2,7 @@
#define FUSEE_FS_UTILS_H
#include "utils.h"
#include "sdmmc.h"
#include "sdmmc/sdmmc.h"
size_t get_file_size(const char *filename);
size_t read_from_file(void *dst, size_t dst_size, const char *filename);

View file

@ -1,3 +1,5 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "hwinit.h"

View file

@ -1,9 +1,6 @@
#ifndef FUSEE_FUSE_H
#define FUSEE_FUSE_H
#include <stdbool.h>
#include <stdint.h>
typedef struct {
uint32_t FUSE_CTRL;
uint32_t FUSE_REG_ADDR;

View file

@ -1,19 +1,9 @@
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include "gpio.h"
enum tegra_gpio_shifts {
GPIO_BANK_SHIFT = 5,
GPIO_PORT_SHIFT = 3,
};
enum tegra_gpio_masks {
GPIO_PORT_MASK = 0x3,
GPIO_PIN_MASK = 0x7,
};
#include "utils.h"
/**
* Returns a GPIO bank object that corresponds to the given GPIO pin,
@ -22,43 +12,39 @@ enum tegra_gpio_masks {
* @param pin The GPIO to get the bank for.
* @return The GPIO bank object to use for working with the given bank.
*/
static volatile struct tegra_gpio_bank *gpio_get_bank(enum tegra_named_gpio pin)
static volatile tegra_gpio_bank_t *gpio_get_bank(uint32_t pin)
{
volatile struct tegra_gpio *gpio = gpio_get_regs();
int bank_number = pin >> GPIO_BANK_SHIFT;
volatile tegra_gpio_t *gpio = gpio_get_regs();
uint32_t bank_number = pin >> GPIO_BANK_SHIFT;
return &gpio->bank[bank_number];
}
/**
* @return the port number for working with the given GPIO.
*/
static volatile int gpio_get_port(enum tegra_named_gpio pin)
static volatile uint32_t gpio_get_port(uint32_t pin)
{
return (pin >> GPIO_PORT_SHIFT) & GPIO_PORT_MASK;
}
/**
* @return a mask to be used to work with the given GPIO
*/
static volatile uint32_t gpio_get_mask(enum tegra_named_gpio pin)
static volatile uint32_t gpio_get_mask(uint32_t pin)
{
uint32_t pin_number = pin & GPIO_PIN_MASK;
return (1 << pin_number);
}
/**
* Performs a simple GPIO configuration operation.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param should_be_set True iff the relevant bit should be set; or false if it should be cleared.
* @param offset The offset into a gpio_bank structure
* @param offset The offset into a gpio_bank structure
*/
static void gpio_simple_register_set(enum tegra_named_gpio pin, bool should_be_set, size_t offset)
static void gpio_simple_register_set(uint32_t pin, bool should_be_set, uint32_t offset)
{
// Retrieve the register set that corresponds to the given pin and offset.
uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset;
@ -66,10 +52,9 @@ static void gpio_simple_register_set(enum tegra_named_gpio pin, bool should_be_s
// Figure out the offset into the cluster,
// and the mask to be used.
int port = gpio_get_port(pin);
uint32_t port = gpio_get_port(pin);
uint32_t mask = gpio_get_mask(pin);
// Set or clear the bit, as appropriate.
if (should_be_set)
cluster[port] |= mask;
@ -77,15 +62,14 @@ static void gpio_simple_register_set(enum tegra_named_gpio pin, bool should_be_s
cluster[port] &= ~mask;
}
/**
* Performs a simple GPIO configuration operation.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param should_be_set True iff the relevant bit should be set; or false if it should be cleared.
* @param offset The offset into a gpio_bank structure
* @param offset The offset into a gpio_bank structure
*/
static bool gpio_simple_register_get(enum tegra_named_gpio pin, size_t offset)
static bool gpio_simple_register_get(uint32_t pin, uint32_t offset)
{
// Retrieve the register set that corresponds to the given pin and offset.
uintptr_t cluster_addr = (uintptr_t)gpio_get_bank(pin) + offset;
@ -93,57 +77,53 @@ static bool gpio_simple_register_get(enum tegra_named_gpio pin, size_t offset)
// Figure out the offset into the cluster,
// and the mask to be used.
int port = gpio_get_port(pin);
uint32_t port = gpio_get_port(pin);
uint32_t mask = gpio_get_mask(pin);
// Convert the given value to a boolean.
return !!(cluster[port] & mask);
}
/**
* Configures a given pin as either GPIO or SFIO.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
void gpio_configure_mode(enum tegra_named_gpio pin, enum tegra_gpio_mode mode)
void gpio_configure_mode(uint32_t pin, uint32_t mode)
{
gpio_simple_register_set(pin, mode == GPIO_MODE_GPIO, offsetof(struct tegra_gpio_bank, config));
gpio_simple_register_set(pin, mode == GPIO_MODE_GPIO, offsetof(tegra_gpio_bank_t, config));
}
/**
* Configures a given pin as either INPUT or OUPUT.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param direction The relevant direction.
*/
void gpio_configure_direction(enum tegra_named_gpio pin, enum tegra_gpio_direction dir)
void gpio_configure_direction(uint32_t pin, uint32_t dir)
{
gpio_simple_register_set(pin, dir == GPIO_DIRECTION_OUTPUT, offsetof(struct tegra_gpio_bank, direction));
gpio_simple_register_set(pin, dir == GPIO_DIRECTION_OUTPUT, offsetof(tegra_gpio_bank_t, direction));
}
/**
* Drives a relevant GPIO pin as either HIGH or LOW.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
void gpio_write(enum tegra_named_gpio pin, enum tegra_gpio_value value)
void gpio_write(uint32_t pin, uint32_t value)
{
gpio_simple_register_set(pin, value == GPIO_LEVEL_HIGH, offsetof(struct tegra_gpio_bank, out));
gpio_simple_register_set(pin, value == GPIO_LEVEL_HIGH, offsetof(tegra_gpio_bank_t, out));
}
/**
* Drives a relevant GPIO pin as either HIGH or LOW.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
enum tegra_gpio_value gpio_read(enum tegra_named_gpio pin)
uint32_t gpio_read(uint32_t pin)
{
return gpio_simple_register_get(pin, offsetof(struct tegra_gpio_bank, in));
return gpio_simple_register_get(pin, offsetof(tegra_gpio_bank_t, in));
}

View file

@ -1,19 +1,14 @@
/*
* Struct defintiions lifted from NVIDIA sample code.
* (C) Copyright 2013-2015 NVIDIA Corporation <www.nvidia.com>
*
* adapted for Fusée by Kate Temkin <k@ktemkin.com.
*/
#ifndef FUSEE_GPIO_H
#define FUSEE_GPIO_H
#ifndef __FUSEE_GPIO_H__
#define __FUSEE_GPIO_H__
#include <stdbool.h>
#include <stdint.h>
#include "utils.h"
enum tegra_gpio_port {
#define TEGRA_GPIO_PORTS 4
#define TEGRA_GPIO_BANKS 8
#define GPIO_BANK_SHIFT 5
#define GPIO_PORT_SHIFT 3
#define GPIO_PORT_MASK 0x03
#define GPIO_PIN_MASK 0x07
typedef enum {
TEGRA_GPIO_PORT_A = 0,
TEGRA_GPIO_PORT_B = 1,
TEGRA_GPIO_PORT_C = 2,
@ -46,25 +41,9 @@ enum tegra_gpio_port {
TEGRA_GPIO_PORT_DD = 29,
TEGRA_GPIO_PORT_EE = 30,
TEGRA_GPIO_PORT_FF = 31,
};
} tegra_gpio_port;
/**
* Convenince macro for computing a GPIO port number.
*/
#define TEGRA_GPIO(port, offset) \
((TEGRA_GPIO_PORT_##port * 8) + offset)
/*
* The Tegra210 GPIO controller has 256 GPIOS in 8 banks of 4 ports,
* each with 8 GPIOs.
*/
enum {
TEGRA_GPIO_PORTS = 4, /* number of ports per bank */
TEGRA_GPIO_BANKS = 8, /* number of banks */
};
/* GPIO Controller registers for a single bank */
struct tegra_gpio_bank {
typedef struct {
uint32_t config[TEGRA_GPIO_PORTS];
uint32_t direction[TEGRA_GPIO_PORTS];
uint32_t out[TEGRA_GPIO_PORTS];
@ -81,94 +60,40 @@ struct tegra_gpio_bank {
uint32_t masked_int_enable[TEGRA_GPIO_PORTS];
uint32_t masked_int_level[TEGRA_GPIO_PORTS];
uint32_t masked_int_clear[TEGRA_GPIO_PORTS];
};
} tegra_gpio_bank_t;
typedef struct {
tegra_gpio_bank_t bank[TEGRA_GPIO_BANKS];
} tegra_gpio_t;
/**
* Representation of Tegra GPIO controllers.
*/
struct tegra_gpio {
struct tegra_gpio_bank bank[TEGRA_GPIO_BANKS];
};
/**
* GPIO pins that have a more detailed functional name,
* specialized for the Switch.
*/
enum tegra_named_gpio {
GPIO_MICROSD_CARD_DETECT = TEGRA_GPIO(Z, 1),
GPIO_MICROSD_WRITE_PROTECT = TEGRA_GPIO(Z, 4),
GPIO_MICROSD_SUPPLY_ENABLE = TEGRA_GPIO(E, 4),
};
/**
* Mode select for GPIO or SFIO.
*/
enum tegra_gpio_mode {
GPIO_MODE_GPIO = 0,
GPIO_MODE_SFIO = 1
};
/**
* GPIO direction values
*/
enum tegra_gpio_direction {
GPIO_DIRECTION_INPUT = 0,
GPIO_DIRECTION_OUTPUT = 1
};
/**
* Active-high GPIO logic
*/
enum tegra_gpio_value {
GPIO_LEVEL_LOW = 0,
GPIO_LEVEL_HIGH = 1
};
/**
* Utility function that grabs the Tegra pinmux registers.
*/
static inline struct tegra_gpio *gpio_get_regs(void)
static inline volatile tegra_gpio_t *gpio_get_regs(void)
{
return (struct tegra_gpio *)0x6000d000;
return (volatile tegra_gpio_t *)0x6000D000;
}
/**
* Configures a given pin as either GPIO or SFIO.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
void gpio_configure_mode(enum tegra_named_gpio pin, enum tegra_gpio_mode mode);
#define TEGRA_GPIO(port, offset) \
((TEGRA_GPIO_PORT_##port * 8) + offset)
/* Mode select */
#define GPIO_MODE_GPIO 0
#define GPIO_MODE_SFIO 1
/**
* Configures a given pin as either INPUT or OUPUT.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param direction The relevant direction.
*/
void gpio_configure_direction(enum tegra_named_gpio pin, enum tegra_gpio_direction dir);
/* Direction */
#define GPIO_DIRECTION_INPUT 0
#define GPIO_DIRECTION_OUTPUT 1
/* Level */
#define GPIO_LEVEL_LOW 0
#define GPIO_LEVEL_HIGH 1
/**
* Drives a relevant GPIO pin as either HIGH or LOW.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant value.
*/
void gpio_write(enum tegra_named_gpio pin, enum tegra_gpio_value value);
/* Named GPIOs */
#define GPIO_MICROSD_CARD_DETECT TEGRA_GPIO(Z, 1)
#define GPIO_MICROSD_WRITE_PROTECT TEGRA_GPIO(Z, 4)
#define GPIO_MICROSD_SUPPLY_ENABLE TEGRA_GPIO(E, 4)
/**
* Drives a relevant GPIO pin as either HIGH or LOW.
*
* @param pin The GPIO pin to work with, as created with TEGRA_GPIO, or a named GPIO.
* @param mode The relevant mode.
*/
enum tegra_gpio_value gpio_read(enum tegra_named_gpio pin);
void gpio_configure_mode(uint32_t pin, uint32_t mode);
void gpio_configure_direction(uint32_t pin, uint32_t dir);
void gpio_write(uint32_t pin, uint32_t value);
uint32_t gpio_read(uint32_t pin);
#endif

View file

@ -5,6 +5,6 @@
#include <stdarg.h>
#define vprintk vprintf
#define printk printf
#define printk printf
#endif

View file

@ -25,11 +25,10 @@ DSTATUS disk_status (
)
{
device_partition_t *devpart = g_volume_to_devparts[pdrv];
if (devpart == NULL) {
return STA_NODISK;
} else {
return devpart->initialized ? 0 : STA_NOINIT;
}
if (devpart)
return devpart->initialized ? RES_OK : STA_NOINIT;
else
return STA_NODISK;
}
@ -44,14 +43,12 @@ DSTATUS disk_initialize (
{
/* We aren't using FF_MULTI_PARTITION, so pdrv = volume id. */
device_partition_t *devpart = g_volume_to_devparts[pdrv];
if (devpart == NULL) {
if (!devpart)
return STA_NODISK;
} else if (devpart->initializer != NULL) {
int rc = devpart->initializer(devpart);
return rc == 0 ? 0 : STA_NOINIT;
} else {
return 0;
}
else if (devpart->initializer)
return devpart->initializer(devpart) ? STA_NOINIT : RES_OK;
else
return RES_OK;
}
@ -69,14 +66,12 @@ DRESULT disk_read (
{
/* We aren't using FF_MULTI_PARTITION, so pdrv = volume id. */
device_partition_t *devpart = g_volume_to_devparts[pdrv];
if (devpart == NULL) {
if (!devpart)
return RES_PARERR;
} else if (devpart->reader != NULL) {
int rc = device_partition_read_data(devpart, buff, sector, count);
return rc == 0 ? 0 : RES_ERROR;
} else {
else if (devpart->reader)
return device_partition_read_data(devpart, buff, sector, count) ? RES_ERROR : RES_OK;
else
return RES_ERROR;
}
}
@ -94,14 +89,12 @@ DRESULT disk_write (
{
/* We aren't using FF_MULTI_PARTITION, so pdrv = volume id. */
device_partition_t *devpart = g_volume_to_devparts[pdrv];
if (devpart == NULL) {
if (!devpart)
return RES_PARERR;
} else if (devpart->writer != NULL) {
int rc = device_partition_write_data(devpart, buff, sector, count);
return rc == 0 ? 0 : RES_ERROR;
} else {
else if (devpart->writer)
return device_partition_write_data(devpart, buff, sector, count) ? RES_ERROR : RES_OK;
else
return RES_ERROR;
}
}
@ -118,11 +111,11 @@ DRESULT disk_ioctl (
{
device_partition_t *devpart = g_volume_to_devparts[pdrv];
switch (cmd) {
case GET_SECTOR_SIZE:
*(WORD *)buff = devpart != NULL ? (WORD)devpart->sector_size : 512;
return 0;
default:
return 0;
case GET_SECTOR_SIZE:
*(WORD *)buff = devpart ? (WORD)devpart->sector_size : 512;
return RES_OK;
default:
return RES_OK;
}
}

View file

@ -12,9 +12,10 @@
#include "nxboot.h"
#include "console.h"
#include "fs_utils.h"
#include "switch_fs.h"
#include "nxfs.h"
#include "gpt.h"
#include "display/video_fb.h"
#include "sdmmc/sdmmc.h"
extern void (*__program_exit_callback)(int rc);
@ -30,7 +31,7 @@ static void setup_env(void) {
/* Set up exception handlers. */
setup_exception_handlers();
if(/*switchfs_import_mmc_structs(&g_stage2_args->sd_mmc, NULL) == -1 ||*/ switchfs_mount_all() == -1) {
if (nxfs_mount_all() < 0) {
fatal_error("Failed to mount at least one parition: %s\n", strerror(errno));
}
@ -39,7 +40,7 @@ static void setup_env(void) {
static void cleanup_env(void) {
/* Unmount everything (this causes all open files to be flushed and closed) */
switchfs_unmount_all();
nxfs_unmount_all();
//console_end();
}
@ -61,12 +62,16 @@ int main(int argc, void **argv) {
if (argc != STAGE2_ARGC) {
generic_panic();
}
g_stage2_args = (stage2_args_t *)argv[STAGE2_ARGV_ARGUMENT_STRUCT];
if(g_stage2_args->version != 0) {
if (g_stage2_args->version != 0) {
generic_panic();
}
/* Set the SDMMC's driver logging level. */
sdmmc_set_log_level(SDMMC_LOG_INFO);
/* Initialize the display, console, FS, etc. */
setup_env();

View file

@ -2,31 +2,40 @@
#include <stdlib.h>
#include <malloc.h>
#include <errno.h>
#include "switch_fs.h"
#include <string.h>
#include "nxfs.h"
#include "gpt.h"
#include "sdmmc.h"
#include "se.h"
#include "hwinit.h"
#include "utils.h"
#include "sdmmc/sdmmc.h"
static bool g_ahb_redirect_enabled = false;
static bool g_sd_mmc_initialized = false;
static bool g_nand_mmc_initialized = false;
static bool g_sd_device_initialized = false;
static bool g_emmc_device_initialized = false;
static bool g_sd_mmc_imported = false;
static bool g_nand_mmc_imported = false;
static sdmmc_t g_sd_sdmmc = {0};
static sdmmc_t g_emmc_sdmmc = {0};
static struct mmc g_sd_mmc = {0};
static struct mmc g_nand_mmc = {0};
static sdmmc_device_t g_sd_device = {0};
static sdmmc_device_t g_emmc_device = {0};
typedef struct mmc_partition_info_t {
struct mmc *mmc;
enum sdmmc_controller controller;
enum sdmmc_partition mmc_partition;
sdmmc_device_t *device;
SdmmcControllerNum controller;
SdmmcPartitionNum partition;
} mmc_partition_info_t;
static mmc_partition_info_t g_sd_mmcpart = {&g_sd_device, SDMMC_1, SDMMC_PARTITION_USER};
static mmc_partition_info_t g_emmc_boot0_mmcpart = {&g_emmc_device, SDMMC_4, SDMMC_PARTITION_BOOT0};
static mmc_partition_info_t g_emmc_boot1_mmcpart = {&g_emmc_device, SDMMC_4, SDMMC_PARTITION_BOOT1};
static mmc_partition_info_t g_emmc_user_mmcpart = {&g_emmc_device, SDMMC_4, SDMMC_PARTITION_USER};
SdmmcPartitionNum g_current_emmc_partition = SDMMC_PARTITION_INVALID;
static int mmc_partition_initialize(device_partition_t *devpart) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
if (devpart->read_cipher != NULL || devpart->write_cipher != NULL) {
devpart->crypto_work_buffer = memalign(16, devpart->sector_size * 16);
if (devpart->crypto_work_buffer == NULL) {
@ -44,27 +53,21 @@ static int mmc_partition_initialize(device_partition_t *devpart) {
g_ahb_redirect_enabled = true;
}
if (mmcpart->mmc == &g_sd_mmc) {
if (!g_sd_mmc_initialized) {
int rc = g_sd_mmc_imported ? 0 : sdmmc_init(mmcpart->mmc, mmcpart->controller, true);
if (rc == 0) {
sdmmc_set_write_enable(mmcpart->mmc, SDMMC_WRITE_ENABLED);
g_sd_mmc_initialized = true;
}
else {
if (mmcpart->device == &g_sd_device) {
if (!g_sd_device_initialized) {
int rc = sdmmc_device_sd_init(mmcpart->device, &g_sd_sdmmc, SDMMC_BUS_WIDTH_4BIT, SDMMC_SPEED_SDR104) ? 0 : EIO;
if (rc)
return rc;
}
g_sd_device_initialized = true;
}
devpart->initialized = true;
return 0;
} else if (mmcpart->mmc == &g_nand_mmc) {
if (!g_nand_mmc_initialized) {
int rc = g_nand_mmc_imported ? 0 : sdmmc_init(mmcpart->mmc, mmcpart->controller, true);
if (rc == 0) {
g_nand_mmc_initialized = true;
} else {
} else if (mmcpart->device == &g_emmc_device) {
if (!g_emmc_device_initialized) {
int rc = sdmmc_device_mmc_init(mmcpart->device, &g_emmc_sdmmc, SDMMC_BUS_WIDTH_8BIT, SDMMC_SPEED_HS400) ? 0 : EIO;
if (rc)
return rc;
}
g_emmc_device_initialized = true;
}
devpart->initialized = true;
return 0;
@ -77,34 +80,31 @@ static void mmc_partition_finalize(device_partition_t *devpart) {
free(devpart->crypto_work_buffer);
}
static enum sdmmc_partition g_current_emmc_partition = (enum sdmmc_partition)-1;
static int mmc_partition_read(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
if (mmcpart->mmc == &g_nand_mmc && g_current_emmc_partition != mmcpart->mmc_partition) {
int rc = sdmmc_select_partition(mmcpart->mmc, mmcpart->mmc_partition);
if (rc != 0 && rc != ENOTTY) {
return rc;
}
g_current_emmc_partition = mmcpart->mmc_partition;
if ((mmcpart->device == &g_emmc_device) && (g_current_emmc_partition != mmcpart->partition)) {
if (!sdmmc_mmc_select_partition(mmcpart->device, mmcpart->partition))
return EIO;
g_current_emmc_partition = mmcpart->partition;
}
return sdmmc_read(mmcpart->mmc, dst, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors);
return sdmmc_device_read(mmcpart->device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, dst) ? 0 : EIO;
}
static int mmc_partition_write(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
if (mmcpart->mmc == &g_nand_mmc && g_current_emmc_partition != mmcpart->mmc_partition) {
int rc = sdmmc_select_partition(mmcpart->mmc, mmcpart->mmc_partition);
if (rc != 0 && rc != ENOTTY) {
return rc;
}
g_current_emmc_partition = mmcpart->mmc_partition;
if ((mmcpart->device == &g_emmc_device) && (g_current_emmc_partition != mmcpart->partition)) {
if (!sdmmc_mmc_select_partition(mmcpart->device, mmcpart->partition))
return EIO;
g_current_emmc_partition = mmcpart->partition;
}
return sdmmc_write(mmcpart->mmc, src, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors);
return sdmmc_device_write(mmcpart->device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, (void *)src) ? 0 : EIO;
}
static int switchfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) {
static int nxfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) {
unsigned int keyslot_a = 4; /* These keyslots are never used by exosphere, and should be safe. */
unsigned int keyslot_b = 5;
size_t size = num_sectors * devpart->sector_size;
@ -124,7 +124,7 @@ static int switchfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sec
}
}
static int switchfs_bis_crypto_encrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) {
static int nxfs_bis_crypto_encrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) {
unsigned int keyslot_a = 4; /* These keyslots are never used by exosphere, and should be safe. */
unsigned int keyslot_b = 5;
size_t size = num_sectors * devpart->sector_size;
@ -144,11 +144,6 @@ static int switchfs_bis_crypto_encrypt(device_partition_t *devpart, uint64_t sec
}
}
static mmc_partition_info_t g_sd_mmcpart = { &g_sd_mmc, SWITCH_MICROSD, SDMMC_PARTITION_USER };
static mmc_partition_info_t g_nand_boot0_mmcpart = { &g_nand_mmc, SWITCH_EMMC, SDMMC_PARTITION_BOOT0 };
static mmc_partition_info_t g_nand_boot1_mmcpart = { &g_nand_mmc, SWITCH_EMMC, SDMMC_PARTITION_BOOT1 };
static mmc_partition_info_t g_nand_user_mmcpart = { &g_nand_mmc, SWITCH_EMMC, SDMMC_PARTITION_USER };
static const device_partition_t g_mmc_devpart_template = {
.sector_size = 512,
.initializer = mmc_partition_initialize,
@ -157,7 +152,7 @@ static const device_partition_t g_mmc_devpart_template = {
.writer = mmc_partition_write,
};
static int switchfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk) {
static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk) {
(void)entry_offset;
(void)disk;
device_partition_t *parent = (device_partition_t *)param;
@ -204,8 +199,8 @@ static int switchfs_mount_partition_gpt_callback(const efi_entry_t *entry, void
}
if (known_partitions[i].is_encrypted) {
devpart.read_cipher = switchfs_bis_crypto_decrypt;
devpart.write_cipher = switchfs_bis_crypto_encrypt;
devpart.read_cipher = nxfs_bis_crypto_decrypt;
devpart.write_cipher = nxfs_bis_crypto_encrypt;
devpart.crypto_mode = DevicePartitionCryptoMode_Xts;
}
@ -238,37 +233,7 @@ static int switchfs_mount_partition_gpt_callback(const efi_entry_t *entry, void
return 0;
}
int switchfs_import_mmc_structs(void *sd, void *nand) {
if (sd != NULL) {
int rc = 0;
memcpy(&g_sd_mmc, sd, sizeof(g_sd_mmc));
rc = sdmmc_import_struct(&g_sd_mmc);
if (rc != 0) {
memset(&g_sd_mmc, 0, sizeof(g_sd_mmc));
errno = rc;
return -1;
} else {
g_sd_mmc_imported = true;
}
}
if (nand != NULL) {
int rc = 0;
memcpy(&g_nand_mmc, nand, sizeof(g_nand_mmc));
rc = sdmmc_import_struct(&g_nand_mmc);
if (rc != 0) {
memset(&g_nand_mmc, 0, sizeof(g_nand_mmc));
errno = rc;
return -1;
} else {
g_nand_mmc_imported = true;
}
}
return 0;
}
int switchfs_mount_all(void) {
int nxfs_mount_all(void) {
device_partition_t model;
int rc;
FILE *rawnand;
@ -278,63 +243,80 @@ int switchfs_mount_all(void) {
model.device_struct = &g_sd_mmcpart;
model.start_sector = 0;
model.num_sectors = 1u << 30; /* arbitrary numbers of sectors. TODO: find the size of the SD in sectors. */
rc = fsdev_mount_device("sdmc", &model, true);
if (rc == -1) {
return -1;
}
rc = fsdev_register_device("sdmc");
if (rc == -1) {
return -1;
}
/* Boot0. */
model = g_mmc_devpart_template;
model.device_struct = &g_nand_boot0_mmcpart;
model.device_struct = &g_emmc_boot0_mmcpart;
model.start_sector = 0;
model.num_sectors = 0x184000 / model.sector_size;
rc = rawdev_mount_device("boot0", &model, true);
if (rc == -1) {
return -1;
}
rc = rawdev_register_device("boot0");
if (rc == -1) {
return -1;
}
/* Boot1. */
model = g_mmc_devpart_template;
model.device_struct = &g_emmc_boot1_mmcpart;
model.start_sector = 0;
model.num_sectors = 0x80000 / model.sector_size;
rc = rawdev_mount_device("boot1", &model, false);
if (rc == -1) {
return -1;
}
/* Boot1. */
model = g_mmc_devpart_template;
model.device_struct = &g_nand_boot1_mmcpart;
model.start_sector = 0;
model.num_sectors = 0x80000 / model.sector_size;
rc = rawdev_mount_device("boot1", &model, false);
if (rc == -1) {
return -1;
}
/* Don't register boot1 for now. */
/* Raw NAND (excluding boot partitions), and its partitions. */
model = g_mmc_devpart_template;
model = g_mmc_devpart_template;
model.device_struct = &g_nand_user_mmcpart;
model.device_struct = &g_emmc_user_mmcpart;
model.start_sector = 0;
model.num_sectors = (32ull << 30) / model.sector_size;
rc = rawdev_mount_device("rawnand", &model, false);
if (rc == -1) {
return -1;
}
rc = rawdev_register_device("rawnand");
if (rc == -1) {
return -1;
}
rawnand = fopen("rawnand:/", "rb");
rc = gpt_iterate_through_entries(rawnand, model.sector_size, switchfs_mount_partition_gpt_callback, &model);
rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model);
fclose(rawnand);
if (rc == 0) {
rc = fsdev_set_default_device("sdmc");
}
return rc;
}
int switchfs_unmount_all(void) {
return fsdev_unmount_all() != 0 || rawdev_unmount_all() != 0 ? -1 : 0;
int nxfs_unmount_all(void) {
return ((fsdev_unmount_all() || rawdev_unmount_all()) ? -1 : 0);
}

View file

@ -0,0 +1,10 @@
#ifndef FUSEE_NX_FS_H
#define FUSEE_NX_FS_H
#include "fs_dev.h"
#include "raw_dev.h"
int nxfs_mount_all(void);
int nxfs_unmount_all(void);
#endif

View file

@ -1,67 +0,0 @@
/**
* Fusée pad control code
* ~ktemkin
*/
#ifndef __FUSEE_PADCTL_H__
#define __FUSEE_PADCTL_H__
#include "utils.h"
/**
* Registers in the Misc Pad control region
*/
struct tegra_padctl {
/* TODO: support registers before? */
uint32_t sdmmc1_control;
uint32_t sdmmc3_control;
uint32_t sdmmc2_control;
uint32_t sdmmc4_control;
/* TODO: support registers after? */
uint8_t _todo[656];
uint32_t vgpio_gpio_mux_sel;
};
/**
* Masks for Pad Control registers
*/
enum tegra_padctl_masks {
/* SDMMC1 */
PADCTL_SDMMC1_DEEP_LOOPBACK = (1 << 0),
/* SDMMC3 */
PADCTL_SDMMC3_DEEP_LOOPBACK = (1 << 0),
/* SDMMC2 */
PADCTL_SDMMC2_ENABLE_DATA_IN = (0xFF << 8),
PADCTL_SDMMC2_ENABLE_CLK_IN = (0x3 << 4),
PADCTL_SDMMC2_DEEP_LOOPBACK = (1 << 0),
/* SDMMC4 */
PADCTL_SDMMC4_ENABLE_DATA_IN = (0xFF << 8),
PADCTL_SDMMC4_ENABLE_CLK_IN = (0x3 << 4),
PADCTL_SDMMC4_DEEP_LOOPBACK = (1 << 0),
/* VGPIO/GPIO */
PADCTL_SDMMC1_CD_SOURCE = (1 << 0),
PADCTL_SDMMC1_WP_SOURCE = (1 << 1),
PADCTL_SDMMC3_CD_SOURCE = (1 << 2),
PADCTL_SDMMC3_WP_SOURCE = (1 << 3),
};
/**
* Utility function that grabs the Tegra PADCTL registers.
*/
static inline struct tegra_padctl *padctl_get_regs(void)
{
return (struct tegra_padctl *)0x700008d4;
}
#endif

View file

@ -1,5 +1,5 @@
#ifndef EXOSPHERE_PANIC_COLOR_H
#define EXOSPHERE_PANIC_COLOR_H
#ifndef FUSEE_PANIC_COLOR_H
#define FUSEE_PANIC_COLOR_H
#define COLOR_0 0x00F00003
#define COLOR_1 0x0F000003

View file

@ -1,14 +1,22 @@
#ifndef __FUSEE_PINMUX_H__
#define __FUSEE_PINMUX_H__
#ifndef FUSEE_PINMUX_H
#define FUSEE_PINMUX_H
#include <stdbool.h>
#include <stdint.h>
#include "utils.h"
#define PINMUX_TRISTATE (1 << 4)
#define PINMUX_PARKED (1 << 5)
#define PINMUX_INPUT (1 << 6)
#define PINMUX_PULL_NONE (0 << 2)
#define PINMUX_PULL_DOWN (1 << 2)
#define PINMUX_PULL_UP (2 << 2)
#define PINMUX_SELECT_FUNCTION0 0
#define PINMUX_SELECT_FUNCTION1 1
#define PINMUX_SELECT_FUNCTION2 2
#define PINMUX_SELECT_FUNCTION3 3
#define PINMUX_DRIVE_1X (0 << 13)
#define PINMUX_DRIVE_2X (1 << 13)
#define PINMUX_DRIVE_3X (2 << 13)
#define PINMUX_DRIVE_4X (3 << 13)
/**
* Pinmux structures.
*/
struct tegra_pinmux {
typedef struct {
uint32_t sdmmc1_clk;
uint32_t sdmmc1_cmd;
uint32_t sdmmc1_dat3;
@ -174,48 +182,11 @@ struct tegra_pinmux {
uint32_t pz3;
uint32_t pz4;
uint32_t pz5;
};
} tegra_pinmux_t;
/**
* Constants for use of the Tegra Pinmux.
*/
enum tegra_pinmux_constants {
/* Tristate (output buffer) control */
PINMUX_TRISTATE = (1 << 4),
/* Park control */
PINMUX_PARKED = (1 << 5),
/* Input control */
PINMUX_INPUT = (1 << 6),
/* Pull resistors */
PINMUX_PULL_NONE = (0 << 2),
PINMUX_PULL_DOWN = (1 << 2),
PINMUX_PULL_UP = (2 << 2),
/* Function select */
PINMUX_SELECT_FUNCTION0 = 0,
PINMUX_SELECT_FUNCTION1 = 1,
PINMUX_SELECT_FUNCTION2 = 2,
PINMUX_SELECT_FUNCTION3 = 3,
/* Drive */
PINMUX_DRIVE_1X = (0x0 << 13),
PINMUX_DRIVE_2X = (0x1 << 13),
PINMUX_DRIVE_3X = (0x2 << 13),
PINMUX_DRIVE_4X = (0x3 << 13),
};
/**
* Utility function that grabs the Tegra pinmux registers.
*/
static inline struct tegra_pinmux *pinmux_get_regs(void)
static inline volatile tegra_pinmux_t *pinmux_get_regs(void)
{
return (struct tegra_pinmux *)0x70003000;
return (volatile tegra_pinmux_t *)0x70003000;
}
#endif

View file

@ -1,37 +1,27 @@
#ifndef __FUSEE_PMC_H__
#define __FUSEE_PMC_H__
#include "utils.h"
#define PMC_BASE 0x7000E400
#ifndef FUSEE_PMC_H
#define FUSEE_PMC_H
/* TODO: get rid of these defines; use the struct instead */
#define PMC_BASE 0x7000E400
#define PMC_CONTROL_SDMMC1 (1 << 12)
#define PMC_CONTROL_SDMMC3 (1 << 13)
#define PMC_CONTROL_SDMMC4 (1 << 14)
#define APBDEV_PMC_CONTROL MAKE_REG32(PMC_BASE + 0x00)
#define APBDEV_PMC_DPD_ENABLE_0 MAKE_REG32(PMC_BASE + 0x24)
#define APBDEV_PMC_PWRGATE_TOGGLE_0 MAKE_REG32(PMC_BASE + 0x30)
#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_REG32(PMC_BASE + 0x38)
#define APBDEV_PMC_SCRATCH0_0 MAKE_REG32(PMC_BASE + 0x50)
#define APBDEV_PMC_CRYPTO_OP_0 MAKE_REG32(PMC_BASE + 0xF4)
#define APBDEV_PM_0 MAKE_REG32(PMC_BASE + 0x14)
#define APBDEV_PMC_WAKE2_STATUS_0 MAKE_REG32(PMC_BASE + 0x168)
#define APBDEV_PMC_RST_STATUS_0 MAKE_REG32(PMC_BASE + 0x1B4)
#define APBDEV_PMC_CNTRL2_0 MAKE_REG32(PMC_BASE + 0x440)
#define APBDEV_PMC_SCRATCH43_0 MAKE_REG32(PMC_BASE + 0x22C)
#define APBDEV_PMC_SCRATCH200_0 MAKE_REG32(PMC_BASE + 0x840)
/**
* Definitions of the Tegra PMC.
* NOTE: Incomplete, do not use
*/
struct tegra_pmc {
typedef struct {
uint32_t cntrl;
uint32_t sec_disable;
uint32_t pmc_swrst;
@ -297,23 +287,11 @@ struct tegra_pmc {
uint32_t scratch118;
uint32_t scratch119;
uint32_t scratch1_eco;
};
} tegra_pmc_t;
enum tegra_pmc_masks {
/* NO_IOPOWER, power detect, ect. */
PMC_CONTROL_SDMMC1 = (1 << 12),
PMC_CONTROL_SDMMC3 = (1 << 13),
PMC_CONTROL_SDMMC4 = (1 << 14),
};
/**
* Utility function that grabs the Tegra PMC registers.
*/
static inline volatile struct tegra_pmc *pmc_get_regs(void)
static inline volatile tegra_pmc_t *pmc_get_regs(void)
{
return (volatile struct tegra_pmc *)0x7000E400;
return (volatile tegra_pmc_t *)0x7000E400;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,313 +0,0 @@
/**
* Fusée SD/MMC driver for the Switch
* ~ktemkin
*/
#ifndef __FUSEE_SDMMC_H__
#define __FUSEE_SDMMC_H__
#include <stdbool.h>
#include <stdint.h>
#include "utils.h"
#include "gpio.h"
/* Opaque pointer to the Tegra SDMMC registers */
struct tegra_sdmmc;
/**
* Bus widths supported by the SD/MMC cards.
*/
enum sdmmc_bus_width {
MMC_BUS_WIDTH_1BIT = 0,
MMC_BUS_WIDTH_4BIT = 1,
MMC_BUS_WIDTH_8BIT = 2,
SD_BUS_WIDTH_1BIT = 0,
SD_BUS_WIDTH_4BIT = 2
};
/**
* Describes the voltages that the host will use to drive the SD card.
* CAUTION: getting these wrong can damage (especially embedded) cards!
*/
enum sdmmc_bus_voltage {
MMC_VOLTAGE_3V3 = 0b111,
MMC_VOLTAGE_1V8 = 0b101,
};
/**
* Represents the different types of devices an MMC object
* can represent.
*/
enum sdmmc_card_type {
MMC_CARD_EMMC,
MMC_CARD_MMC,
MMC_CARD_SD,
MMC_CARD_CART,
};
/**
* Specification versions for SD/MMC cards.
*/
enum sdmmc_spec_version {
/* MMC card versions */
MMC_VERSION_4 = 0,
/* SD card versions */
SD_VERSION_1_0 = 0,
SD_VERSION_1_1 = 1,
SD_VERSION_2_0 = 2,
};
/**
* SDMMC controllers
*/
enum sdmmc_controller {
SWITCH_MICROSD = 0,
SWITCH_EMMC = 3
};
/**
* Write permission modes for SD cards.
*/
enum sdmmc_write_permission {
SDMMC_WRITE_DISABLED,
SDMMC_WRITE_ENABLED,
/* use this with the utmost caution so you don't wind up with a brick */
SDMMC_WRITE_ENABLED_INCLUDING_EMMC,
};
/**
* Methods by which we can touch registers accessed via.
* CMD_SWITCH_MODE.
*/
enum sdmmc_switch_access_mode {
/* Normal commands */
MMC_SWITCH_MODE_CMD_SET = 0,
MMC_SWITCH_MODE_SET_BITS = 1,
MMC_SWITCH_MODE_CLEAR_BITS = 2,
MMC_SWITCH_MODE_WRITE_BYTE = 3,
/* EXTCSD access */
MMC_SWITCH_EXTCSD_NORMAL = 1,
};
/**
* Offsets into the SWITCH_MODE argument.
*/
enum sdmmc_switch_argument_offsets {
MMC_SWITCH_VALUE_SHIFT = 8,
MMC_SWITCH_FIELD_SHIFT = 16,
MMC_SWITCH_ACCESS_MODE_SHIFT = 24,
};
/**
* Bus speeds possible for an SDMMC controller.
*/
enum sdmmc_bus_speed {
/* SD card speeds */
SDMMC_SPEED_SDR12 = 0,
SDMMC_SPEED_SDR25 = 1,
SDMMC_SPEED_SDR50 = 2,
SDMMC_SPEED_SDR104 = 3,
SDMMC_SPEED_DDR50 = 4,
/* Other speed: non-spec-compliant value used for e.g. HS400 */
SDMMC_SPEED_OTHER = 5,
/* eMMC card speeds */
/* note: to avoid an enum clash, we add ten to these */
SDMMC_SPEED_HS26 = 10 ,
SDMMC_SPEED_HS52 = 11 ,
SDMMC_SPEED_HS200 = 12 ,
SDMMC_SPEED_HS400 = 13 ,
/* special speeds */
SDMMC_SPEED_INIT = -1,
};
/**
* Primary data structure describing a Fusée MMC driver.
*/
struct mmc {
enum sdmmc_controller controller;
/* Controller properties */
const char *name;
bool use_dma;
bool allow_voltage_switching;
unsigned int timeout;
enum tegra_named_gpio card_detect_gpio;
enum sdmmc_write_permission write_enable;
/* Per-controller operations. */
int (*set_up_clock_and_io)(struct mmc *mmc);
void (*configure_clock)(struct mmc *mmc, uint32_t source, int car_divisor, int sdmmc_divisor);
int (*enable_supplies)(struct mmc *mmc);
int (*switch_to_low_voltage)(struct mmc *mmc);
bool (*card_present)(struct mmc *mmc);
/* Per-card-type operations */
int (*card_init)(struct mmc *mmc);
int (*establish_relative_address)(struct mmc *mmc);
int (*switch_mode)(struct mmc *mmc, int a, int b, int c, uint32_t timeout, void *response);
int (*switch_bus_width)(struct mmc *mmc, enum sdmmc_bus_width width);
int (*optimize_speed)(struct mmc *mmc);
int (*card_switch_bus_speed)(struct mmc *mmc, enum sdmmc_bus_speed speed);
/* Card properties */
enum sdmmc_card_type card_type;
uint32_t mmc_card_type;
uint8_t cid[15];
uint32_t relative_address;
uint8_t partitioned;
enum sdmmc_spec_version spec_version;
enum sdmmc_bus_width max_bus_width;
enum sdmmc_bus_voltage operating_voltage;
enum sdmmc_bus_speed operating_speed;
uint8_t partition_support;
uint8_t partition_config;
uint8_t partition_attribute;
uint32_t partition_switch_time;
uint8_t read_block_order;
uint8_t write_block_order;
uint8_t tuning_block_order;
bool uses_block_addressing;
/* Current operation status flags */
uint32_t active_data_buffer;
/* Pointers to hardware structures */
volatile struct tegra_sdmmc *regs;
};
/**
* Primary data structure describing a Fusée MMC driver.
*/
struct mmc;
/**
* Parititions supported by the Switch eMMC.
*/
enum sdmmc_partition {
SDMMC_PARTITION_USER = 0,
SDMMC_PARTITION_BOOT0 = 1,
SDMMC_PARTITION_BOOT1 = 2,
};
/**
* Sets the current SDMMC debugging loglevel.
*
* @param loglevel Current log level. A higher value prints more logs.
* @return The loglevel prior to when this was applied, for easy restoration.
*/
int sdmmc_set_loglevel(int loglevel);
/**
* Set up a new SDMMC driver.
*
* @param mmc The SDMMC structure to be initiailized with the device state.
* @param controler The controller description to be used; usually SWITCH_EMMC
* or SWITCH_MICROSD.
* @param allow_voltage_switching True if we should allow voltage switching,
* which may not make sense if we're about to chainload to another component without
* preseving the overall structure.
*/
int sdmmc_init(struct mmc *mmc, enum sdmmc_controller controller, bool allow_voltage_switching);
/**
* Imports a SDMMC driver struct from another program. This mainly intended for stage2,
* so that it can reuse stage1's SDMMC struct instance(s).
*
* @param mmc The SDMMC structure to be imported.
*/
int sdmmc_import_struct(struct mmc *mmc);
/**
* Selects the active MMC partition. Can be used to select
* boot partitions for access. Affects all operations going forward.
*
* @param mmc The MMC controller whose card is to be used.
* @param partition The partition number to be selected.
*
* @return 0 on success, or an error code on failure.
*/
int sdmmc_select_partition(struct mmc *mmc, enum sdmmc_partition partition);
/**
* Reads a sector or sectors from a given SD card.
*
* @param mmc The MMC device to work with.
* @param buffer The output buffer to target.
* @param sector The sector number to read.
* @param count The number of sectors to read.
*/
int sdmmc_read(struct mmc *mmc, void *buffer, uint32_t sector, unsigned int count);
/**
* Releases the SDMMC write lockout, enabling access to the card.
* Note that by default, setting this to WRITE_ENABLED will not allow access to eMMC.
* Check the source for a third constant that can be used to enable eMMC writes.
*
* @param perms The permissions to apply-- typically WRITE_DISABLED or WRITE_ENABLED.
*/
void sdmmc_set_write_enable(struct mmc *mmc, enum sdmmc_write_permission perms);
/**
* Writes a sector or sectors to a given SD/MMC card.
*
* @param mmc The MMC device to work with.
* @param buffer The input buffer to write.
* @param block The sector number to write from.
* @param count The number of sectors to write.
*
* @return 0 on success, or an error code on failure.
*/
int sdmmc_write(struct mmc *mmc, const void *buffer, uint32_t block, unsigned int count);
/**
* Checks to see whether an SD card is present.
*
* @mmc mmc The controller with which to check for card presence.
* @return true iff a card is present
*/
bool sdmmc_card_present(struct mmc *mmc);
/**
* Prints out all of the tegra_mmc struct fields
*
* @mmc mmc The controller with which to dump registers.
*/
void sdmmc_dump_regs(struct mmc *mmc);
#endif

View file

@ -0,0 +1,448 @@
/*
* Header for MultiMediaCard (MMC)
*
* Copyright 2002 Hewlett-Packard Company
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
* FITNESS FOR ANY PARTICULAR PURPOSE.
*
* Many thanks to Alessandro Rubini and Jonathan Corbet!
*
* Based strongly on code by:
*
* Author: Yong-iL Joh <tolkien@mizi.com>
*
* Author: Andrew Christian
* 15 May 2002
*/
#ifndef LINUX_MMC_MMC_H
#define LINUX_MMC_MMC_H
/* Standard MMC commands (4.1) type argument response */
/* class 1 */
#define MMC_GO_IDLE_STATE 0 /* bc */
#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
#define MMC_ALL_SEND_CID 2 /* bcr R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define MMC_SET_DSR 4 /* bc [31:16] RCA */
#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
#define MMC_BUS_TEST_R 14 /* adtc R1 */
#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
#define MMC_BUS_TEST_W 19 /* adtc R1 */
#define MMC_SPI_READ_OCR 58 /* spi spi_R3 */
#define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */
/* class 2 */
#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */
#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
/* class 3 */
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
/* class 4 */
#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
#define MMC_PROGRAM_CID 26 /* adtc R1 */
#define MMC_PROGRAM_CSD 27 /* adtc R1 */
/* class 6 */
#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
/* class 5 */
#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
#define MMC_ERASE 38 /* ac R1b */
/* class 9 */
#define MMC_FAST_IO 39 /* ac <Complex> R4 */
#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
/* class 7 */
#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
/* class 8 */
#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
/* class 11 */
#define MMC_QUE_TASK_PARAMS 44 /* ac [20:16] task id R1 */
#define MMC_QUE_TASK_ADDR 45 /* ac [31:0] data addr R1 */
#define MMC_EXECUTE_READ_TASK 46 /* adtc [20:16] task id R1 */
#define MMC_EXECUTE_WRITE_TASK 47 /* adtc [20:16] task id R1 */
#define MMC_CMDQ_TASK_MGMT 48 /* ac [20:16] task id R1b */
/*
* MMC_SWITCH argument format:
*
* [31:26] Always 0
* [25:24] Access Mode
* [23:16] Location of target Byte in EXT_CSD
* [15:08] Value Byte
* [07:03] Always 0
* [02:00] Command Set
*/
/*
MMC status in R1, for native mode (SPI bits are different)
Type
e : error bit
s : status bit
r : detected and set for the actual command response
x : detected and set during command execution. the host must poll
the card by sending status command in order to read these bits.
Clear condition
a : according to the card state
b : always related to the previous command. Reception of
a valid command will clear it (with a delay of one command)
c : clear by read
*/
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
#define R1_ERASE_PARAM (1 << 27) /* ex, c */
#define R1_WP_VIOLATION (1 << 26) /* erx, c */
#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
#define R1_CC_ERROR (1 << 20) /* erx, c */
#define R1_ERROR (1 << 19) /* erx, c */
#define R1_UNDERRUN (1 << 18) /* ex, c */
#define R1_OVERRUN (1 << 17) /* ex, c */
#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
#define R1_ERASE_RESET (1 << 13) /* sr, c */
#define R1_STATUS(x) (x & 0xFFFFE000)
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
#define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */
#define R1_APP_CMD (1 << 5) /* sr, c */
#define R1_STATE_IDLE 0
#define R1_STATE_READY 1
#define R1_STATE_IDENT 2
#define R1_STATE_STBY 3
#define R1_STATE_TRAN 4
#define R1_STATE_DATA 5
#define R1_STATE_RCV 6
#define R1_STATE_PRG 7
#define R1_STATE_DIS 8
/*
* MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS
* R1 is the low order byte; R2 is the next highest byte, when present.
*/
#define R1_SPI_IDLE (1 << 0)
#define R1_SPI_ERASE_RESET (1 << 1)
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
#define R1_SPI_COM_CRC (1 << 3)
#define R1_SPI_ERASE_SEQ (1 << 4)
#define R1_SPI_ADDRESS (1 << 5)
#define R1_SPI_PARAMETER (1 << 6)
/* R1 bit 7 is always zero */
#define R2_SPI_CARD_LOCKED (1 << 8)
#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */
#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
#define R2_SPI_ERROR (1 << 10)
#define R2_SPI_CC_ERROR (1 << 11)
#define R2_SPI_CARD_ECC_ERROR (1 << 12)
#define R2_SPI_WP_VIOLATION (1 << 13)
#define R2_SPI_ERASE_PARAM (1 << 14)
#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
/*
* OCR bits are mostly in host.h
*/
#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
/*
* Card Command Classes (CCC)
*/
#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */
/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
/* (and for SPI, CMD58,59) */
#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */
/* (CMD11) */
#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */
/* (CMD16,17,18) */
#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */
/* (CMD20) */
#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */
/* (CMD16,24,25,26,27) */
#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */
/* (CMD32,33,34,35,36,37,38,39) */
#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */
/* (CMD28,29,30) */
#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */
/* (CMD16,CMD42) */
#define CCC_APP_SPEC (1<<8) /* (8) Application specific */
/* (CMD55,56,57,ACMD*) */
#define CCC_IO_MODE (1<<9) /* (9) I/O mode */
/* (CMD5,39,40,52,53) */
#define CCC_SWITCH (1<<10) /* (10) High speed switch */
/* (CMD6,34,35,36,37,50) */
/* (11) Reserved */
/* (CMD?) */
/*
* CSD field definitions
*/
#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */
#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */
#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
/*
* EXT_CSD fields
*/
#define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
#define EXT_CSD_BKOPS_EN 163 /* R/W */
#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_FW_CONFIG 169 /* R/W */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_STROBE_SUPPORT 184 /* RO */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_POWER_CLASS 187 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_DRIVER_STRENGTH 197 /* RO */
#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
#define EXT_CSD_PWR_CL_26_195 201 /* RO */
#define EXT_CSD_PWR_CL_52_360 202 /* RO */
#define EXT_CSD_PWR_CL_26_360 203 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
#define EXT_CSD_BOOT_MULT 226 /* RO */
#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */
#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
#define EXT_CSD_TRIM_MULT 232 /* RO */
#define EXT_CSD_PWR_CL_200_195 236 /* RO */
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
#define EXT_CSD_BKOPS_STATUS 246 /* RO */
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
#define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */
#define EXT_CSD_PRE_EOL_INFO 267 /* RO */
#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */
#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */
#define EXT_CSD_CMDQ_DEPTH 307 /* RO */
#define EXT_CSD_CMDQ_SUPPORT 308 /* RO */
#define EXT_CSD_SUPPORTED_MODE 493 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
* EXT_CSD field definitions
*/
#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)
#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10)
#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04)
#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01)
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SETTING_COMPLETED (0x1)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
#define EXT_CSD_CMD_SET_SECURE (1<<1)
#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
#define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */
#define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \
EXT_CSD_CARD_TYPE_HS_52)
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
/* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */
#define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
EXT_CSD_CARD_TYPE_HS200_1_2V)
#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */
#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */
#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \
EXT_CSD_CARD_TYPE_HS400_1_2V)
#define EXT_CSD_CARD_TYPE_HS400ES (1<<8) /* Card can run at HS400ES */
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_BUS_WIDTH_STROBE BIT(7) /* Enhanced strobe mode */
#define EXT_CSD_TIMING_BC 0 /* Backwards compatility */
#define EXT_CSD_TIMING_HS 1 /* High speed */
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_TIMING_HS400 3 /* HS400 */
#define EXT_CSD_DRV_STR_SHIFT 4 /* Driver Strength shift */
#define EXT_CSD_SEC_ER_EN BIT(0)
#define EXT_CSD_SEC_BD_BLK_EN BIT(2)
#define EXT_CSD_SEC_GB_CL_EN BIT(4)
#define EXT_CSD_SEC_SANITIZE BIT(6) /* v4.5 only */
#define EXT_CSD_RST_N_EN_MASK 0x3
#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
#define EXT_CSD_NO_POWER_NOTIFICATION 0
#define EXT_CSD_POWER_ON 1
#define EXT_CSD_POWER_OFF_SHORT 2
#define EXT_CSD_POWER_OFF_LONG 3
#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
#define EXT_CSD_PACKED_EVENT_EN BIT(3)
/*
* EXCEPTION_EVENT_STATUS field
*/
#define EXT_CSD_URGENT_BKOPS BIT(0)
#define EXT_CSD_DYNCAP_NEEDED BIT(1)
#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
#define EXT_CSD_PACKED_FAILURE BIT(3)
#define EXT_CSD_PACKED_GENERIC_ERROR BIT(0)
#define EXT_CSD_PACKED_INDEXED_ERROR BIT(1)
/*
* BKOPS status level
*/
#define EXT_CSD_BKOPS_LEVEL_2 0x2
/*
* BKOPS modes
*/
#define EXT_CSD_MANUAL_BKOPS_MASK 0x01
#define EXT_CSD_AUTO_BKOPS_MASK 0x02
/*
* Command Queue
*/
#define EXT_CSD_CMDQ_MODE_ENABLED BIT(0)
#define EXT_CSD_CMDQ_DEPTH_MASK GENMASK(4, 0)
#define EXT_CSD_CMDQ_SUPPORTED BIT(0)
/*
* MMC_SWITCH access modes
*/
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
/*
* Erase/trim/discard
*/
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000
#define MMC_TRIM_ARG 0x00000001
#define MMC_DISCARD_ARG 0x00000003
#define MMC_SECURE_TRIM1_ARG 0x80000001
#define MMC_SECURE_TRIM2_ARG 0x80008000
#define MMC_SECURE_ARGS 0x80000000
#define MMC_TRIM_ARGS 0x00008001
#endif /* LINUX_MMC_MMC_H */

View file

@ -0,0 +1,153 @@
/*
* include/linux/mmc/sd.h
*
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*/
#ifndef LINUX_MMC_SD_H
#define LINUX_MMC_SD_H
/* SD commands type argument response */
/* class 0 */
/* This is basically the same command as for MMC with some quirks. */
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
#define SD_SWITCH_VOLTAGE 11 /* ac R1 */
/* class 10 */
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
/* class 5 */
#define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */
#define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */
/* Application commands */
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
#define SD_APP_SD_STATUS 13 /* adtc R1 */
#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
#define SD_APP_SET_CLR_CARD_DETECT 42 /* ac [0] set cd R1 */
#define SD_APP_SEND_SCR 51 /* adtc R1 */
/* OCR bit definitions */
#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */
#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */
#define SD_OCR_XPC (1 << 28) /* SDXC power control */
#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */
#define SD_OCR_VDD_LOW (1 << 7) /* SD: Reserved for Low Voltage Range */
#define SD_OCR_VDD_20_21 (1 << 8)
#define SD_OCR_VDD_21_22 (1 << 9)
#define SD_OCR_VDD_22_23 (1 << 10)
#define SD_OCR_VDD_23_24 (1 << 11)
#define SD_OCR_VDD_24_25 (1 << 12)
#define SD_OCR_VDD_25_26 (1 << 13)
#define SD_OCR_VDD_26_27 (1 << 14)
#define SD_OCR_VDD_27_28 (1 << 15)
#define SD_OCR_VDD_28_29 (1 << 16)
#define SD_OCR_VDD_29_30 (1 << 17)
#define SD_OCR_VDD_30_31 (1 << 18)
#define SD_OCR_VDD_31_32 (1 << 19)
#define SD_OCR_VDD_32_33 (1 << 20)
#define SD_OCR_VDD_33_34 (1 << 21)
#define SD_OCR_VDD_34_35 (1 << 22)
#define SD_OCR_VDD_35_36 (1 << 23)
/*
* SD_SWITCH argument format:
*
* [31] Check (0) or switch (1)
* [30:24] Reserved (0)
* [23:20] Function group 6
* [19:16] Function group 5
* [15:12] Function group 4
* [11:8] Function group 3
* [7:4] Function group 2
* [3:0] Function group 1
*/
/*
* SD_SEND_IF_COND argument format:
*
* [31:12] Reserved (0)
* [11:8] Host Voltage Supply Flags
* [7:0] Check Pattern (0xAA)
*/
/*
* SCR field definitions
*/
#define SD_SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
#define SD_SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
#define SD_SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */
#define SD_SCR_BUS_WIDTH_1 1
#define SD_SCR_BUS_WIDTH_4 4
#define SD_SCR_CMD20_SUPPORT 1
#define SD_SCR_CMD23_SUPPORT 2
/*
* SD bus widths
*/
#define SD_BUS_WIDTH_1 0
#define SD_BUS_WIDTH_4 2
/*
* SD bus speed modes
*/
#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 SD_MODE_HIGH_SPEED (1 << HIGH_SPEED_BUS_SPEED)
#define SD_MODE_UHS_SDR12 (1 << UHS_SDR12_BUS_SPEED)
#define SD_MODE_UHS_SDR25 (1 << UHS_SDR25_BUS_SPEED)
#define SD_MODE_UHS_SDR50 (1 << UHS_SDR50_BUS_SPEED)
#define SD_MODE_UHS_SDR104 (1 << UHS_SDR104_BUS_SPEED)
#define SD_MODE_UHS_DDR50 (1 << UHS_DDR50_BUS_SPEED)
/*
* SD bus driver types
*/
#define SD_DRIVER_TYPE_B 0x01
#define SD_DRIVER_TYPE_A 0x02
#define SD_DRIVER_TYPE_C 0x04
#define SD_DRIVER_TYPE_D 0x08
/*
* SD bus current limits
*/
#define SD_SET_CURRENT_LIMIT_200 0
#define SD_SET_CURRENT_LIMIT_400 1
#define SD_SET_CURRENT_LIMIT_600 2
#define SD_SET_CURRENT_LIMIT_800 3
#define SD_SET_CURRENT_NO_CHANGE (-1)
#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
*/
#define SD_SWITCH_CHECK 0
#define SD_SWITCH_SET 1
/*
* SD_SWITCH function groups
*/
#define SD_SWITCH_GRP_ACCESS 0
/*
* SD_SWITCH access modes
*/
#define SD_SWITCH_ACCESS_DEF 0
#define SD_SWITCH_ACCESS_HS 1
#endif /* LINUX_MMC_SD_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,161 @@
#ifndef FUSEE_SDMMC_H
#define FUSEE_SDMMC_H
#include "sdmmc_core.h"
/* Structure for storing the MMC CID (adapted from Linux headers) */
typedef struct {
uint32_t manfid;
uint8_t prod_name[8];
uint8_t prv;
uint32_t serial;
uint16_t oemid;
uint16_t year;
uint8_t hwrev;
uint8_t fwrev;
uint8_t month;
} mmc_cid_t;
/* Structure for storing the MMC CSD (adapted from Linux headers) */
typedef struct {
uint8_t structure;
uint8_t mmca_vsn;
uint16_t cmdclass;
uint16_t taac_clks;
uint32_t taac_ns;
uint32_t c_size;
uint32_t r2w_factor;
uint32_t max_dtr;
uint32_t erase_size; /* In sectors */
uint32_t read_blkbits;
uint32_t write_blkbits;
uint32_t capacity;
uint32_t read_partial:1,
read_misalign:1,
write_partial:1,
write_misalign:1,
dsr_imp:1;
} mmc_csd_t;
/* Structure for storing the MMC extended CSD (adapted from Linux headers) */
typedef struct {
uint8_t rev;
uint8_t erase_group_def;
uint8_t sec_feature_support;
uint8_t rel_sectors;
uint8_t rel_param;
uint8_t part_config;
uint8_t cache_ctrl;
uint8_t rst_n_function;
uint8_t max_packed_writes;
uint8_t max_packed_reads;
uint8_t packed_event_en;
uint32_t part_time; /* Units: ms */
uint32_t sa_timeout; /* Units: 100ns */
uint32_t generic_cmd6_time; /* Units: 10ms */
uint32_t power_off_longtime; /* Units: ms */
uint8_t power_off_notification; /* state */
uint32_t hs_max_dtr;
uint32_t hs200_max_dtr;
uint32_t sectors;
uint32_t hc_erase_size; /* In sectors */
uint32_t hc_erase_timeout; /* In milliseconds */
uint32_t sec_trim_mult; /* Secure trim multiplier */
uint32_t sec_erase_mult; /* Secure erase multiplier */
uint32_t trim_timeout; /* In milliseconds */
uint32_t partition_setting_completed; /* enable bit */
uint64_t enhanced_area_offset; /* Units: Byte */
uint32_t enhanced_area_size; /* Units: KB */
uint32_t cache_size; /* Units: KB */
uint32_t hpi_en; /* HPI enablebit */
uint32_t hpi; /* HPI support bit */
uint32_t hpi_cmd; /* cmd used as HPI */
uint32_t bkops; /* background support bit */
uint32_t man_bkops_en; /* manual bkops enable bit */
uint32_t auto_bkops_en; /* auto bkops enable bit */
uint32_t data_sector_size; /* 512 bytes or 4KB */
uint32_t data_tag_unit_size; /* DATA TAG UNIT size */
uint32_t boot_ro_lock; /* ro lock support */
uint32_t boot_ro_lockable;
uint32_t ffu_capable; /* Firmware upgrade support */
uint32_t cmdq_en; /* Command Queue enabled */
uint32_t cmdq_support; /* Command Queue supported */
uint32_t cmdq_depth; /* Command Queue depth */
uint8_t fwrev[8]; /* FW version */
uint8_t raw_exception_status; /* 54 */
uint8_t raw_partition_support; /* 160 */
uint8_t raw_rpmb_size_mult; /* 168 */
uint8_t raw_erased_mem_count; /* 181 */
uint8_t strobe_support; /* 184 */
uint8_t raw_ext_csd_structure; /* 194 */
uint8_t raw_card_type; /* 196 */
uint8_t raw_driver_strength; /* 197 */
uint8_t out_of_int_time; /* 198 */
uint8_t raw_pwr_cl_52_195; /* 200 */
uint8_t raw_pwr_cl_26_195; /* 201 */
uint8_t raw_pwr_cl_52_360; /* 202 */
uint8_t raw_pwr_cl_26_360; /* 203 */
uint8_t raw_s_a_timeout; /* 217 */
uint8_t raw_hc_erase_gap_size; /* 221 */
uint8_t raw_erase_timeout_mult; /* 223 */
uint8_t raw_hc_erase_grp_size; /* 224 */
uint8_t raw_sec_trim_mult; /* 229 */
uint8_t raw_sec_erase_mult; /* 230 */
uint8_t raw_sec_feature_support; /* 231 */
uint8_t raw_trim_mult; /* 232 */
uint8_t raw_pwr_cl_200_195; /* 236 */
uint8_t raw_pwr_cl_200_360; /* 237 */
uint8_t raw_pwr_cl_ddr_52_195; /* 238 */
uint8_t raw_pwr_cl_ddr_52_360; /* 239 */
uint8_t raw_pwr_cl_ddr_200_360; /* 253 */
uint8_t raw_bkops_status; /* 246 */
uint8_t raw_sectors[4]; /* 212 - 4 bytes */
uint8_t pre_eol_info; /* 267 */
uint8_t device_life_time_est_typ_a; /* 268 */
uint8_t device_life_time_est_typ_b; /* 269 */
uint32_t feature_support;
} mmc_ext_csd_t;
/* Structure for storing the SD SCR (adapted from Linux headers) */
typedef struct {
uint8_t sda_vsn;
uint8_t sda_spec3;
uint8_t bus_widths;
uint8_t cmds;
} sd_scr_t;
/* Structure for storing the SD SSR (adapted from Linux headers) */
typedef struct {
uint8_t dat_bus_width;
uint8_t secured_mode;
uint16_t sd_card_type;
uint8_t speed_class;
uint8_t uhs_speed_grade;
uint8_t uhs_au_size;
uint8_t video_speed_class;
uint8_t app_perf_class;
} sd_ssr_t;
/* Structure describing a SDMMC device's context. */
typedef struct {
/* Underlying driver context. */
sdmmc_t *sdmmc;
bool is_180v;
bool is_block_sdhc;
uint32_t rca;
mmc_cid_t cid;
mmc_csd_t csd;
mmc_ext_csd_t ext_csd;
sd_scr_t scr;
sd_ssr_t ssr;
} sdmmc_device_t;
int sdmmc_device_sd_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth bus_width, SdmmcBusSpeed bus_speed);
int sdmmc_device_mmc_init(sdmmc_device_t *device, sdmmc_t *sdmmc, SdmmcBusWidth bus_width, SdmmcBusSpeed bus_speed);
int sdmmc_device_read(sdmmc_device_t *device, uint32_t sector, uint32_t num_sectors, void *data);
int sdmmc_device_write(sdmmc_device_t *device, uint32_t sector, uint32_t num_sectors, void *data);
int sdmmc_device_finish(sdmmc_device_t *device);
int sdmmc_mmc_select_partition(sdmmc_device_t *device, SdmmcPartitionNum partition);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,298 @@
#ifndef FUSEE_SDMMC_CORE_H
#define FUSEE_SDMMC_CORE_H
#include "sdmmc_tegra.h"
/* Bounce buffer */
#define SDMMC_BOUNCE_BUFFER_ADDRESS 0x90000000
/* Present state */
#define SDHCI_CMD_INHIBIT 0x00000001
#define SDHCI_DATA_INHIBIT 0x00000002
#define SDHCI_DOING_WRITE 0x00000100
#define SDHCI_DOING_READ 0x00000200
#define SDHCI_SPACE_AVAILABLE 0x00000400
#define SDHCI_DATA_AVAILABLE 0x00000800
#define SDHCI_CARD_PRESENT 0x00010000
#define SDHCI_WRITE_PROTECT 0x00080000
#define SDHCI_DATA_LVL_MASK 0x00F00000
#define SDHCI_DATA_LVL_SHIFT 20
#define SDHCI_DATA_0_LVL_MASK 0x00100000
#define SDHCI_CMD_LVL 0x01000000
/* SDHCI clock control */
#define SDHCI_DIVIDER_SHIFT 8
#define SDHCI_DIVIDER_HI_SHIFT 6
#define SDHCI_DIV_MASK 0xFF
#define SDHCI_DIV_MASK_LEN 8
#define SDHCI_DIV_HI_MASK 0x300
#define SDHCI_PROG_CLOCK_MODE 0x0020
#define SDHCI_CLOCK_CARD_EN 0x0004
#define SDHCI_CLOCK_INT_STABLE 0x0002
#define SDHCI_CLOCK_INT_EN 0x0001
/* SDHCI 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
/* SDHCI host control 2 */
#define SDHCI_CTRL_UHS_MASK 0x0007
#define SDHCI_CTRL_UHS_SDR12 0x0000
#define SDHCI_CTRL_UHS_SDR25 0x0001
#define SDHCI_CTRL_UHS_SDR50 0x0002
#define SDHCI_CTRL_UHS_SDR104 0x0003
#define SDHCI_CTRL_UHS_DDR50 0x0004
#define SDHCI_CTRL_HS400 0x0005
#define SDHCI_CTRL_VDD_180 0x0008
#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
#define SDHCI_CTRL_DRV_TYPE_B 0x0000
#define SDHCI_CTRL_DRV_TYPE_A 0x0010
#define SDHCI_CTRL_DRV_TYPE_C 0x0020
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
#define SDHCI_CTRL_EXEC_TUNING 0x0040
#define SDHCI_CTRL_TUNED_CLK 0x0080
#define SDHCI_UHS2_IF_EN 0x0100
#define SDHCI_HOST_VERSION_4_EN 0x1000
#define SDHCI_ADDRESSING_64BIT_EN 0x2000
#define SDHCI_ASYNC_INTR_EN 0x4000
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
/* SDHCI capabilities */
#define SDHCI_CAN_DO_8BIT 0x00040000
#define SDHCI_CAN_DO_ADMA2 0x00080000
#define SDHCI_CAN_DO_ADMA1 0x00100000
#define SDHCI_CAN_DO_HISPD 0x00200000
#define SDHCI_CAN_DO_SDMA 0x00400000
#define SDHCI_CAN_VDD_330 0x01000000
#define SDHCI_CAN_VDD_300 0x02000000
#define SDHCI_CAN_VDD_180 0x04000000
#define SDHCI_CAN_64BIT 0x10000000
#define SDHCI_ASYNC_INTR 0x20000000
/* Vendor clock control */
#define SDMMC_CLOCK_TAP_MASK (0xFF << 16)
#define SDMMC_CLOCK_TAP_SDMMC1 (0x04 << 16)
#define SDMMC_CLOCK_TAP_SDMMC2 (0x00 << 16)
#define SDMMC_CLOCK_TAP_SDMMC3 (0x03 << 16)
#define SDMMC_CLOCK_TAP_SDMMC4 (0x00 << 16)
#define SDMMC_CLOCK_TRIM_MASK (0xFF << 24)
#define SDMMC_CLOCK_TRIM_SDMMC1 (0x02 << 24)
#define SDMMC_CLOCK_TRIM_SDMMC2 (0x08 << 24)
#define SDMMC_CLOCK_TRIM_SDMMC3 (0x03 << 24)
#define SDMMC_CLOCK_TRIM_SDMMC4 (0x08 << 24)
#define SDMMC_CLOCK_PADPIPE_CLKEN_OVERRIDE (1 << 3)
/* Autocal configuration */
#define SDMMC_AUTOCAL_PDPU_CONFIG_MASK 0x7F7F
#define SDMMC_AUTOCAL_PDPU_SDMMC1_1V8 0x7B7B
#define SDMMC_AUTOCAL_PDPU_SDMMC1_3V3 0x7D00
#define SDMMC_AUTOCAL_PDPU_SDMMC4_1V8 0x0505
#define SDMMC_AUTOCAL_START (1 << 31)
#define SDMMC_AUTOCAL_ENABLE (1 << 29)
/* Autocal status */
#define SDMMC_AUTOCAL_ACTIVE (1 << 31)
/* Vendor tuning control 0*/
#define SDMMC_VENDOR_TUNING_TRIES_MASK (0x7 << 13)
#define SDMMC_VENDOR_TUNING_TRIES_SHIFT 13
#define SDMMC_VENDOR_TUNING_MULTIPLIER_MASK (0x7F << 6)
#define SDMMC_VENDOR_TUNING_MULTIPLIER_UNITY (1 << 6)
#define SDMMC_VENDOR_TUNING_DIVIDER_MASK (0x7 << 3)
#define SDMMC_VENDOR_TUNING_SET_BY_HW (1 << 17)
/* Vendor tuning control 1*/
#define SDMMC_VENDOR_TUNING_STEP_SIZE_SDR50_DEFAULT (0 << 0)
#define SDMMC_VENDOR_TUNING_STEP_SIZE_SDR104_DEFAULT (0 << 4)
/* Vendor capability overrides */
#define SDMMC_VENDOR_CAPABILITY_DQS_TRIM_MASK (0x3F << 8)
#define SDMMC_VENDOR_CAPABILITY_DQS_TRIM_HS400 (0x11 << 8)
/* Timeouts */
#define SDMMC_AUTOCAL_TIMEOUT (10 * 1000)
#define SDMMC_TUNING_TIMEOUT (150 * 1000)
/* Command response flags */
#define SDMMC_RSP_PRESENT (1 << 0)
#define SDMMC_RSP_136 (1 << 1)
#define SDMMC_RSP_CRC (1 << 2)
#define SDMMC_RSP_BUSY (1 << 3)
#define SDMMC_RSP_OPCODE (1 << 4)
/* Command types */
#define SDMMC_CMD_MASK (3 << 5)
#define SDMMC_CMD_AC (0 << 5)
#define SDMMC_CMD_ADTC (1 << 5)
#define SDMMC_CMD_BC (2 << 5)
#define SDMMC_CMD_BCR (3 << 5)
/* SPI command response flags */
#define SDMMC_RSP_SPI_S1 (1 << 7)
#define SDMMC_RSP_SPI_S2 (1 << 8)
#define SDMMC_RSP_SPI_B4 (1 << 9)
#define SDMMC_RSP_SPI_BUSY (1 << 10)
/* Native response types for commands */
#define SDMMC_RSP_NONE (0)
#define SDMMC_RSP_R1 (SDMMC_RSP_PRESENT|SDMMC_RSP_CRC|SDMMC_RSP_OPCODE)
#define SDMMC_RSP_R1B (SDMMC_RSP_PRESENT|SDMMC_RSP_CRC|SDMMC_RSP_OPCODE|SDMMC_RSP_BUSY)
#define SDMMC_RSP_R2 (SDMMC_RSP_PRESENT|SDMMC_RSP_136|SDMMC_RSP_CRC)
#define SDMMC_RSP_R3 (SDMMC_RSP_PRESENT)
#define SDMMC_RSP_R4 (SDMMC_RSP_PRESENT)
#define SDMMC_RSP_R5 (SDMMC_RSP_PRESENT|SDMMC_RSP_CRC|SDMMC_RSP_OPCODE)
#define SDMMC_RSP_R6 (SDMMC_RSP_PRESENT|SDMMC_RSP_CRC|SDMMC_RSP_OPCODE)
#define SDMMC_RSP_R7 (SDMMC_RSP_PRESENT|SDMMC_RSP_CRC|SDMMC_RSP_OPCODE)
#define SDMMC_RSP_R1_NO_CRC (SDMMC_RSP_PRESENT|SDMMC_RSP_OPCODE)
/* SPI response types for commands */
#define SDMMC_RSP_SPI_R1 (SDMMC_RSP_SPI_S1)
#define SDMMC_RSP_SPI_R1B (SDMMC_RSP_SPI_S1|SDMMC_RSP_SPI_BUSY)
#define SDMMC_RSP_SPI_R2 (SDMMC_RSP_SPI_S1|SDMMC_RSP_SPI_S2)
#define SDMMC_RSP_SPI_R3 (SDMMC_RSP_SPI_S1|SDMMC_RSP_SPI_B4)
#define SDMMC_RSP_SPI_R4 (SDMMC_RSP_SPI_S1|SDMMC_RSP_SPI_B4)
#define SDMMC_RSP_SPI_R5 (SDMMC_RSP_SPI_S1|SDMMC_RSP_SPI_S2)
#define SDMMC_RSP_SPI_R7 (SDMMC_RSP_SPI_S1|SDMMC_RSP_SPI_B4)
/* Internal logging */
typedef enum {
SDMMC_LOG_NONE = 0,
SDMMC_LOG_ERROR = 1,
SDMMC_LOG_WARN = 2,
SDMMC_LOG_INFO = 3,
SDMMC_LOG_DEBUG = 4
} SdmmcLogLevel;
/* SDMMC controllers */
typedef enum {
SDMMC_1 = 0,
SDMMC_2 = 1,
SDMMC_3 = 2,
SDMMC_4 = 3
} SdmmcControllerNum;
typedef enum {
SDMMC_PARTITION_INVALID = -1,
SDMMC_PARTITION_USER = 0,
SDMMC_PARTITION_BOOT0 = 1,
SDMMC_PARTITION_BOOT1 = 2,
SDMMC_PARTITION_RPMB = 3
} SdmmcPartitionNum;
typedef enum {
SDMMC_VOLTAGE_NONE = 0,
SDMMC_VOLTAGE_1V8 = 1,
SDMMC_VOLTAGE_3V3 = 2
} SdmmcBusVoltage;
typedef enum {
SDMMC_BUS_WIDTH_1BIT = 0,
SDMMC_BUS_WIDTH_4BIT = 1,
SDMMC_BUS_WIDTH_8BIT = 2
} SdmmcBusWidth;
typedef enum {
SDMMC_SPEED_INIT_HS = 0,
SDMMC_SPEED_HS26 = 1,
SDMMC_SPEED_HS52 = 2,
SDMMC_SPEED_HS200 = 3,
SDMMC_SPEED_HS400 = 4,
SDMMC_SPEED_INIT_SDR = 5,
SDMMC_SPEED_UNK6 = 6,
SDMMC_SPEED_SDR25 = 7,
SDMMC_SPEED_SDR12 = 8,
SDMMC_SPEED_UNK9 = 9,
SDMMC_SPEED_SDR50 = 10,
SDMMC_SPEED_SDR104 = 11,
SDMMC_SPEED_UNK12 = 12,
SDMMC_SPEED_DDR50 = 13,
SDMMC_SPEED_UNK14 = 14,
} SdmmcBusSpeed;
typedef enum {
SDMMC_CAR_DIVIDER_SDR12 = 31, // (16.5 * 2) - 2
SDMMC_CAR_DIVIDER_SDR25 = 15, // (8.5 * 2) - 2
SDMMC_CAR_DIVIDER_SDR50 = 7, // (4.5 * 2) - 2
SDMMC_CAR_DIVIDER_SDR104 = 2, // (2 * 2) - 2
SDMMC_CAR_DIVIDER_DDR50 = 18, // (5 * 2 * 2) - 2
SDMMC_CAR_DIVIDER_HS26 = 30, // (16 * 2) - 2
SDMMC_CAR_DIVIDER_HS52 = 14, // (8 * 2) - 2
SDMMC_CAR_DIVIDER_HS200 = 3, // (2.5 * 2) - 2 (for PLLP_OUT0)
SDMMC_CAR_DIVIDER_HS400 = 3, // (2.5 * 2) - 2 (for PLLP_OUT0)
} SdmmcCarDivider;
/* Structure for describing a SDMMC device. */
typedef struct {
/* Controller number */
SdmmcControllerNum controller;
/* Backing register space */
volatile tegra_sdmmc_t *regs;
/* Controller properties */
const char *name;
bool has_sd;
bool is_clk_running;
bool is_sd_clk_enabled;
bool is_tuning_tap_val_set;
bool use_adma;
uint32_t tap_val;
uint32_t internal_divider;
uint32_t resp[4];
uint32_t resp_auto_cmd12;
uint32_t next_dma_addr;
uint8_t* dma_bounce_buf;
SdmmcBusVoltage bus_voltage;
SdmmcBusWidth bus_width;
/* Per-controller operations. */
int (*sdmmc_config)();
} sdmmc_t;
/* Structure for describing a SDMMC command. */
typedef struct {
uint32_t opcode;
uint32_t arg;
uint32_t resp[4];
uint32_t flags; /* expected response type */
} sdmmc_command_t;
/* Structure for describing a SDMMC request. */
typedef struct {
void* data;
uint32_t blksz;
uint32_t num_blocks;
bool is_multi_block;
bool is_read;
bool is_auto_cmd12;
} sdmmc_request_t;
int sdmmc_init(sdmmc_t *sdmmc, SdmmcControllerNum controller, SdmmcBusVoltage bus_voltage, SdmmcBusWidth bus_width, SdmmcBusSpeed bus_speed);
void sdmmc_finish(sdmmc_t *sdmmc);
int sdmmc_select_speed(sdmmc_t *sdmmc, SdmmcBusSpeed bus_speed);
void sdmmc_select_bus_width(sdmmc_t *sdmmc, SdmmcBusWidth width);
void sdmmc_select_voltage(sdmmc_t *sdmmc, SdmmcBusVoltage voltage);
void sdmmc_adjust_sd_clock(sdmmc_t *sdmmc);
int sdmmc_switch_voltage(sdmmc_t *sdmmc);
void sdmmc_set_tuning_tap_val(sdmmc_t *sdmmc);
int sdmmc_execute_tuning(sdmmc_t *sdmmc, SdmmcBusSpeed bus_speed, uint32_t opcode);
int sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_command_t *cmd, sdmmc_request_t *req, uint32_t *num_blocks_out);
int sdmmc_load_response(sdmmc_t *sdmmc, uint32_t flags, uint32_t *resp);
int sdmmc_abort(sdmmc_t *sdmmc, uint32_t opcode);
void sdmmc_set_log_level(SdmmcLogLevel log_level);
void sdmmc_error(sdmmc_t *sdmmc, char *fmt, ...);
void sdmmc_warn(sdmmc_t *sdmmc, char *fmt, ...);
void sdmmc_info(sdmmc_t *sdmmc, char *fmt, ...);
void sdmmc_debug(sdmmc_t *sdmmc, char *fmt, ...);
void sdmmc_dump_regs(sdmmc_t *sdmmc);
#endif

View file

@ -0,0 +1,154 @@
#ifndef FUSEE_SDMMC_TEGRA_H
#define FUSEE_SDMMC_TEGRA_H
#include <stdbool.h>
#include <stdint.h>
#define TEGRA_MMC_PWRCTL_SD_BUS_POWER (1 << 0)
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8 (5 << 1)
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0 (6 << 1)
#define TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3 (7 << 1)
#define TEGRA_MMC_HOSTCTL_DMASEL_MASK (3 << 3)
#define TEGRA_MMC_HOSTCTL_DMASEL_SDMA (0 << 3)
#define TEGRA_MMC_HOSTCTL_DMASEL_ADMA2_32BIT (2 << 3)
#define TEGRA_MMC_HOSTCTL_DMASEL_ADMA2_64BIT (3 << 3)
#define TEGRA_MMC_TRNMOD_DMA_ENABLE (1 << 0)
#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE (1 << 1)
#define TEGRA_MMC_TRNMOD_AUTO_CMD12 (1 << 2)
#define TEGRA_MMC_TRNMOD_AUTO_CMD23 (1 << 3)
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE (0 << 4)
#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ (1 << 4)
#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT (1 << 5)
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK (3 << 0)
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE (0 << 0)
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 (1 << 0)
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 (2 << 0)
#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY (3 << 0)
#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK (1 << 3)
#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK (1 << 4)
#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER (1 << 5)
#define TEGRA_MMC_PRNSTS_CMD_INHIBIT_CMD (1 << 0)
#define TEGRA_MMC_PRNSTS_CMD_INHIBIT_DAT (1 << 1)
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE (1 << 0)
#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE (1 << 1)
#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE (1 << 2)
#define TEGRA_MMC_CLKCON_PROG_CLOCK_MODE (1 << 5)
#define TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_SHIFT 8
#define TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_MASK (0xff << 8)
#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL (1 << 0)
#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE (1 << 1)
#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE (1 << 2)
#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE (1 << 0)
#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE (1 << 1)
#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT (1 << 3)
#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT (1 << 15)
#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT (1 << 16)
#define TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE (1 << 0)
#define TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE (1 << 1)
#define TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT (1 << 3)
#define TEGRA_MMC_NORINTSTSEN_BUFFER_WRITE_READY (1 << 4)
#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY (1 << 5)
#define TEGRA_MMC_NORINTSIGEN_XFER_COMPLETE (1 << 1)
typedef struct {
/* SDHCI standard registers */
uint32_t dma_address;
uint16_t block_size;
uint16_t block_count;
uint32_t argument;
uint16_t transfer_mode;
uint16_t command;
uint32_t response[0x4];
uint32_t buffer;
uint32_t present_state;
uint8_t host_control;
uint8_t power_control;
uint8_t block_gap_control;
uint8_t wake_up_control;
uint16_t clock_control;
uint8_t timeout_control;
uint8_t software_reset;
uint32_t int_status;
uint32_t int_enable;
uint32_t signal_enable;
uint16_t acmd12_err;
uint16_t host_control2;
uint32_t capabilities;
uint32_t capabilities_1;
uint32_t max_current;
uint32_t _0x4c;
uint16_t set_acmd12_error;
uint16_t set_int_error;
uint8_t adma_error;
uint8_t _0x56[0x3];
uint32_t adma_address;
uint32_t upper_adma_address;
uint16_t preset_for_init;
uint16_t preset_for_default;
uint16_t preset_for_high;
uint16_t preset_for_sdr12;
uint16_t preset_for_sdr25;
uint16_t preset_for_sdr50;
uint16_t preset_for_sdr104;
uint16_t preset_for_ddr50;
uint32_t _0x70[0x23];
uint16_t slot_int_status;
uint16_t host_version;
/* vendor specific registers */
uint32_t vendor_clock_cntrl;
uint32_t vendor_sys_sw_cntrl;
uint32_t vendor_err_intr_status;
uint32_t vendor_cap_overrides;
uint32_t vendor_boot_cntrl;
uint32_t vendor_boot_ack_timeout;
uint32_t vendor_boot_dat_timeout;
uint32_t vendor_debounce_count;
uint32_t vendor_misc_cntrl;
uint32_t max_current_override;
uint32_t max_current_override_hi;
uint32_t _0x12c[0x20];
uint32_t vendor_io_trim_cntrl;
/* start of sdmmc2/sdmmc4 only */
uint32_t vendor_dllcal_cfg;
uint32_t vendor_dll_ctrl0;
uint32_t vendor_dll_ctrl1;
uint32_t vendor_dllcal_cfg_sta;
/* end of sdmmc2/sdmmc4 only */
uint32_t vendor_tuning_cntrl0;
uint32_t vendor_tuning_cntrl1;
uint32_t vendor_tuning_status0;
uint32_t vendor_tuning_status1;
uint32_t vendor_clk_gate_hysteresis_count;
uint32_t vendor_preset_val0;
uint32_t vendor_preset_val1;
uint32_t vendor_preset_val2;
uint32_t sdmemcomppadctrl;
uint32_t auto_cal_config;
uint32_t auto_cal_interval;
uint32_t auto_cal_status;
uint32_t io_spare;
uint32_t sdmmca_mccif_fifoctrl;
uint32_t timeout_wcoal_sdmmca;
uint32_t _0x1fc;
} tegra_sdmmc_t;
static inline volatile tegra_sdmmc_t *sdmmc_get_regs(uint32_t idx)
{
return (volatile tegra_sdmmc_t *)(0x700B0000 + (idx * 0x200));
}
#endif

View file

@ -438,7 +438,7 @@ void aes_128_xts_nintendo_crypt_sector(unsigned int keyslot_1, unsigned int keys
SECURITY_ENGINE->CRYPTO_REG = keyslot_1 << 24;
}
SECURITY_ENGINE->BLOCK_COUNT_REG = (size >> 4) - 1;
trigger_se_blocking_op(OP_START, dst, size, dst, size);
trigger_se_blocking_op(OP_START, dst, size, src, size);
/* XOR. */
aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, dst, size);

View file

@ -1,7 +1,6 @@
#ifndef FUSEE_SE_H
#define FUSEE_SE_H
#include "utils.h"
#include <assert.h>
#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x2
@ -206,4 +205,4 @@ bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const v
void se_initialize_rng(unsigned int keyslot);
void se_generate_random(unsigned int keyslot, void *dst, size_t size);
#endif /* EXOSPHERE_SE_H */
#endif

View file

@ -2,7 +2,7 @@
#define FUSEE_STAGE2_H
#include "utils.h"
#include "sdmmc.h"
#include "sdmmc/sdmmc.h"
/* TODO: Is there a more concise way to do this? */
#define STAGE2_ARGV_PROGRAM_PATH 0
@ -13,7 +13,6 @@
typedef struct {
uint32_t version;
//struct mmc sd_mmc;
bool display_initialized;
char bct0[BCTO_MAX_SIZE];
} stage2_args_t;

View file

@ -1,37 +0,0 @@
/**
* Fusée power supply control code
* ~ktemkin
*/
#include "lib/driver_utils.h"
#include "supplies.h"
// FIXME: replace hwinit with our own code
#include "hwinit/max7762x.h"
/**
* Enables a given power supply.
*
* @param supply The power domain on the Switch that is to be enabled.
* @param use_low_voltage If the supply supports multiple voltages, use the lower one.
* Some devices start in a high power mode, but an can be switched to a lower one.
* Set this to false unless you know what you're doing.
*/
void supply_enable(enum switch_power_supply supply, bool use_low_voltage)
{
uint32_t voltage = 0;
switch(supply) {
case SUPPLY_MICROSD:
voltage = use_low_voltage ? SUPPLY_MICROSD_LOW_VOLTAGE : SUPPLY_MICROSD_VOLTAGE;
max77620_regulator_set_voltage(SUPPLY_MICROSD_REGULATOR, voltage);
max77620_regulator_enable(SUPPLY_MICROSD_REGULATOR, true);
return;
default:
printk("ERROR: could not enable unknown supply %d!\n", supply);
return;
}
}

View file

@ -1,36 +0,0 @@
/**
* Fusée power supply control code
* ~ktemkin
*/
#ifndef __FUSEE_SUPPLIES_H__
#define __FUSEE_SUPPLIES_H__
#include "utils.h"
enum switch_power_supply {
SUPPLY_MICROSD,
};
enum switch_power_constants {
/* MicroSD card */
SUPPLY_MICROSD_REGULATOR = 6,
SUPPLY_MICROSD_VOLTAGE = 3300000,
SUPPLY_MICROSD_LOW_VOLTAGE = 1800000,
};
/**
* Enables a given power supply.
*
* @param supply The power domain on the Switch that is to be enabled.
* @param use_low_voltage If the supply supports multiple voltages, use the lower one.
* Some devices start in a high power mode, but an can be switched to a lower one.
* Set this to false unless you know what you're doing.
*/
void supply_enable(enum switch_power_supply supply, bool use_low_voltage);
#endif

View file

@ -1,12 +0,0 @@
#ifndef FUSEE_SWITCH_FS_H
#define FUSEE_SWITCH_FS_H
#include "fs_dev.h"
#include "raw_dev.h"
int switchfs_import_mmc_structs(void *sd, void *nand);
int switchfs_mount_all(void);
int switchfs_unmount_all(void);
#endif

View file

@ -4,11 +4,14 @@
#include "utils.h"
#define TIMERS_BASE 0x60005000
#define MAKE_TIMERS_REG(n) MAKE_REG32(TIMERS_BASE + n)
#define TIMERUS_CNTR_1US_0 MAKE_REG32(TIMERS_BASE + 0x10)
#define RTC_BASE 0x7000E000
#define RTC_SECONDS MAKE_REG32(RTC_BASE + 0x08)
#define RTC_SHADOW_SECONDS MAKE_REG32(RTC_BASE + 0x0C)
#define RTC_MILLI_SECONDS MAKE_REG32(RTC_BASE + 0x10)
typedef struct {
uint32_t CONFIG;
uint32_t STATUS;
@ -22,24 +25,46 @@ typedef struct {
void wait(uint32_t microseconds);
static inline uint32_t get_time(void) {
static inline uint32_t get_time_s(void) {
return RTC_SECONDS;
}
static inline uint32_t get_time_ms(void) {
return (RTC_MILLI_SECONDS | (RTC_SHADOW_SECONDS << 10));
}
static inline uint32_t get_time_us(void) {
return TIMERUS_CNTR_1US_0;
}
/**
* Returns the time in microseconds.
*/
static inline uint32_t get_time(void) {
return get_time_us();
}
/**
* Returns the number of microseconds that have passed since a given get_time().
*/
static inline uint32_t get_time_since(uint32_t base) {
return get_time() - base;
return get_time_us() - base;
}
/**
* Delays for a given number of microseconds.
*/
static inline void udelay(unsigned usecs)
{
uint32_t start = get_time();
while (get_time() - start < usecs) ;
static inline void udelay(uint32_t usecs) {
uint32_t start = get_time_us();
while (get_time_us() - start < usecs);
}
/**
* Delays for a given number of milliseconds.
*/
static inline void mdelay(uint32_t msecs) {
uint32_t start = get_time_ms();
while (get_time_ms() - start < msecs);
}
__attribute__ ((noreturn)) void watchdog_reboot(void);