From 617d1e9f6b7969aff5e45746b9c5e3cee9ce2c45 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Thu, 30 Jun 2011 17:31:40 +0000 Subject: imx233/fuze+: ssp, dma, mmc now work properly, partially implement cpu frequency changing, implement panic waiting git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30104 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/imx233/mmc-imx233.c | 146 +++++++++++++++++++++++++++++--- 1 file changed, 132 insertions(+), 14 deletions(-) (limited to 'firmware/target/arm/imx233/mmc-imx233.c') diff --git a/firmware/target/arm/imx233/mmc-imx233.c b/firmware/target/arm/imx233/mmc-imx233.c index f56ff3725c..dafe63f3d3 100644 --- a/firmware/target/arm/imx233/mmc-imx233.c +++ b/firmware/target/arm/imx233/mmc-imx233.c @@ -22,36 +22,54 @@ #include "system.h" #include "mmc.h" #include "sdmmc.h" +#include "storage.h" #include "ssp-imx233.h" #include "pinctrl-imx233.h" #include "button-target.h" +/** + * This code assumes a single eMMC internal flash + */ + #ifdef SANSA_FUZEPLUS #define MMC_SSP 2 #else #error You need to configure the ssp to use #endif +#define MMC_RCA 1 + +/** When set, this values restrict the windows of the read and writes */ +static unsigned mmc_window_start = 0; +static unsigned mmc_window_end = INT_MAX; + +static struct mutex mmc_mutex; + 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 */ + /** 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 @ 120MHz - * gives bitrate of 120 / 100 / 3 = 400kHz */ - imx233_ssp_set_timings(MMC_SSP, 100, 2); - imx233_ssp_set_timeout(MMC_SSP, 0xffff); + /* 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, SD_GO_IDLE_STATE, 0, SSP_NO_RESP, NULL, 0, false, NULL); + int ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, SD_GO_IDLE_STATE, 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 */ @@ -59,18 +77,82 @@ int mmc_init(void) do { uint32_t ocr; - ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 1, 0x40ff8000, SSP_SHORT_RESP, NULL, 0, false, &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, cid); + 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; } @@ -81,13 +163,49 @@ int mmc_num_drives(int first_drive) return 1; } -int mmc_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf) +#ifdef STORAGE_GET_INFO +void mmc_get_info(IF_MD2(int drive,) struct storage_info *info) +{ +#ifdef HAVE_MULTIDRIVE + (void) drive; +#endif + info->sector_size = 512; + info->num_sectors = 0xECC000 - 0x0001ac00; + info->vendor = "Rockbox"; + info->product = "Internal Storage"; + info->revision = "0.00"; +} +#endif + +int mmc_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void *buf) { IF_MD((void) drive); - (void) start; - (void) count; - (void) buf; - return -1; + /* check window */ + start += mmc_window_start; + if((start + count) > mmc_window_end) + return -201; + /* get mutex (needed because we done multiple commands for count > 0 */ + mutex_lock(&mmc_mutex); + int ret = 0; + uint32_t resp; + + if(count == 1) + { + ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 17, start, SSP_SHORT_RESP, buf, + count, false, true, &resp); + } + else + { + ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 23, count, SSP_SHORT_RESP, NULL, + 0, false, false, &resp); + if(ret == 0) + ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 18, start, SSP_SHORT_RESP, buf, + count, false, true, &resp); + } + + mutex_unlock(&mmc_mutex); + + return ret; } int mmc_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf) -- cgit v1.2.3