Пример #1
0
void power_off(void)
{
    /* wait a bit, useful for the user to stop touching anything */
    sleep(HZ / 2);
#ifdef SANSA_FUZEPLUS
    /* This pin seems to be important to shutdown the hardware properly */
    imx233_pinctrl_acquire_pin(0, 9, "power off");
    imx233_set_pin_function(0, 9, PINCTRL_FUNCTION_GPIO);
    imx233_enable_gpio_output(0, 9, true);
    imx233_set_gpio_output(0, 9, true);
#endif
    /* power down */
    HW_POWER_RESET = HW_POWER_RESET__UNLOCK | HW_POWER_RESET__PWD;
    while(1);
}
Пример #2
0
int mmc_init(void)
{
    mutex_init(&mmc_mutex);
    
    imx233_ssp_start(MMC_SSP);
    imx233_ssp_softreset(MMC_SSP);
    imx233_ssp_set_mode(MMC_SSP, HW_SSP_CTRL1__SSP_MODE__SD_MMC);
    #ifdef SANSA_FUZEPLUS
    /** Sansa Fuze+ has an internal eMMC 8-bit wide flash, power gate is pin PWM3
     * and power up time is 20ms */
    imx233_set_pin_function(1, 29, PINCTRL_FUNCTION_GPIO);
    imx233_enable_gpio_output(1, 29, true);
    imx233_set_gpio_output(1, 29, false);
    sleep(HZ / 5);

    imx233_ssp_setup_ssp2_sd_mmc_pins(true, 8, PINCTRL_DRIVE_8mA);
    #endif
    /* SSPCLK @ 96MHz
     * gives bitrate of 96000 / 240 / 1 = 400kHz */
    imx233_ssp_set_timings(MMC_SSP, 240, 0, 0xffff);
    imx233_ssp_sd_mmc_power_up_sequence(MMC_SSP);
    imx233_ssp_set_bus_width(MMC_SSP, 1);
    imx233_ssp_set_block_size(MMC_SSP, 9);
    /* go to idle state */
    int ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 0, 0, SSP_NO_RESP, NULL, 0, false, false, NULL);
    if(ret != 0)
        return -1;
    /* send op cond until the card respond with busy bit set; it must complete within 1sec */
    unsigned timeout = current_tick + HZ;
    do
    {
        uint32_t ocr;
        ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 1, 0x40ff8000, SSP_SHORT_RESP, NULL, 0, false, false, &ocr);
        if(ret == 0 && ocr & (1 << 31))
            break;
    }while(!TIME_AFTER(current_tick, timeout));

    if(ret != 0)
        return -2;
    /* get CID */
    uint32_t cid[4];
    ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 2, 0, SSP_LONG_RESP, NULL, 0, false, false, cid);
    if(ret != 0)
        return -3;
    /* Set RCA */
    uint32_t status;
    ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 3, MMC_RCA << 16, SSP_SHORT_RESP, NULL, 0, false, false, &status);
    if(ret != 0)
        return -4;
    /* Select card */
    ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 7, MMC_RCA << 16, SSP_SHORT_RESP, NULL, 0, false, false, &status);
    if(ret != 0)
        return -5;
    /* Check TRAN state */
    ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 13, MMC_RCA << 16, SSP_SHORT_RESP, NULL, 0, false, false, &status);
    if(ret != 0)
        return -6;
    if(((status >> 9) & 0xf) != 4)
        return -7;
    /* Switch to 8-bit bus */
    ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 6, 0x3b70200, SSP_SHORT_RESP, NULL, 0, true, false, &status);
    if(ret != 0)
        return -8;
    /* switch error ? */
    if(status & 0x80)
        return -9;
    imx233_ssp_set_bus_width(MMC_SSP, 8);
    /* Switch to high speed mode */
    ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 6, 0x3b90100, SSP_SHORT_RESP, NULL, 0, true, false, &status);
    if(ret != 0)
        return -10;
    /* switch error ?*/
    if(status & 0x80)
        return -11;
    /* SSPCLK @ 96MHz
     * gives bitrate of 96 / 2 / 1 = 48MHz */
    imx233_ssp_set_timings(MMC_SSP, 2, 0, 0xffff);

    #ifdef SANSA_FUZEPLUS
    /**
     * The Fuze+ uses a strange layout: is has a first MBR at sector 0 with four entries:
     * 1) Actual user partition
     * 2) Sigmatel boot partition
     * 3)4) Other (certificate related ?) partitions
     * The partition 1) has type 1 but it's actually a type 5 (logical partition) with
     * a second partition table with usually one entry which is the FAT32 one.
     * The first table uses 512-byte sector size and the second one usually uses
     * 2048-byte logical sector size.
     *
     * We restrict mmc window to the user partition */
    uint8_t mbr[512];
    mmc_window_start = 0;
    mmc_window_end = INT_MAX;
    ret = mmc_read_sectors(IF_MD2(0,) 0, 1, mbr);
    if(ret != 0)
        return -100;
    if(mbr[510] != 0x55 || mbr[511] != 0xAA)
        return -101; /* invalid MBR */
    /* sanity check that the first partition is greater than 2Gib */
    uint8_t *ent = &mbr[446];
    mmc_window_start = ent[8] | ent[9] << 8 | ent[10] << 16 | ent[11] << 24;
    mmc_window_end = (ent[12] | ent[13] << 8 | ent[14] << 16 | ent[15] << 24) +
        mmc_window_start;
    if(ent[4] == 0x53)
        return -102; /* sigmatel partition */
    if((mmc_window_end - mmc_window_start) < 4 * 1024 * 1024)
        return -103; /* partition too small */
    #endif

    return 0;
}