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);