summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/mmc-imx233.c
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2011-06-30 17:31:40 +0000
committerAmaury Pouly <pamaury@rockbox.org>2011-06-30 17:31:40 +0000
commit617d1e9f6b7969aff5e45746b9c5e3cee9ce2c45 (patch)
treebf2015d298c2b6bc80189d09b73426380e08451f /firmware/target/arm/imx233/mmc-imx233.c
parent4a04c47a97517930b29f00b9d7f4d157cb69fa9b (diff)
downloadrockbox-617d1e9f6b7969aff5e45746b9c5e3cee9ce2c45.tar.gz
rockbox-617d1e9f6b7969aff5e45746b9c5e3cee9ce2c45.zip
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
Diffstat (limited to 'firmware/target/arm/imx233/mmc-imx233.c')
-rw-r--r--firmware/target/arm/imx233/mmc-imx233.c146
1 files changed, 132 insertions, 14 deletions
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 @@
22#include "system.h" 22#include "system.h"
23#include "mmc.h" 23#include "mmc.h"
24#include "sdmmc.h" 24#include "sdmmc.h"
25#include "storage.h"
25#include "ssp-imx233.h" 26#include "ssp-imx233.h"
26#include "pinctrl-imx233.h" 27#include "pinctrl-imx233.h"
27#include "button-target.h" 28#include "button-target.h"
28 29
30/**
31 * This code assumes a single eMMC internal flash
32 */
33
29#ifdef SANSA_FUZEPLUS 34#ifdef SANSA_FUZEPLUS
30#define MMC_SSP 2 35#define MMC_SSP 2
31#else 36#else
32#error You need to configure the ssp to use 37#error You need to configure the ssp to use
33#endif 38#endif
34 39
40#define MMC_RCA 1
41
42/** When set, this values restrict the windows of the read and writes */
43static unsigned mmc_window_start = 0;
44static unsigned mmc_window_end = INT_MAX;
45
46static struct mutex mmc_mutex;
47
35int mmc_init(void) 48int mmc_init(void)
36{ 49{
50 mutex_init(&mmc_mutex);
51
37 imx233_ssp_start(MMC_SSP); 52 imx233_ssp_start(MMC_SSP);
38 imx233_ssp_softreset(MMC_SSP); 53 imx233_ssp_softreset(MMC_SSP);
39 imx233_ssp_set_mode(MMC_SSP, HW_SSP_CTRL1__SSP_MODE__SD_MMC); 54 imx233_ssp_set_mode(MMC_SSP, HW_SSP_CTRL1__SSP_MODE__SD_MMC);
40 #ifdef SANSA_FUZEPLUS 55 #ifdef SANSA_FUZEPLUS
41 /** Sansa Fuze+ has an internal eMMC 8-bit wide flash, power gate is pin PWM3 */ 56 /** Sansa Fuze+ has an internal eMMC 8-bit wide flash, power gate is pin PWM3
57 * and power up time is 20ms */
42 imx233_set_pin_function(1, 29, PINCTRL_FUNCTION_GPIO); 58 imx233_set_pin_function(1, 29, PINCTRL_FUNCTION_GPIO);
43 imx233_enable_gpio_output(1, 29, true); 59 imx233_enable_gpio_output(1, 29, true);
44 imx233_set_gpio_output(1, 29, false); 60 imx233_set_gpio_output(1, 29, false);
61 sleep(HZ / 5);
45 62
46 imx233_ssp_setup_ssp2_sd_mmc_pins(true, 8, PINCTRL_DRIVE_8mA); 63 imx233_ssp_setup_ssp2_sd_mmc_pins(true, 8, PINCTRL_DRIVE_8mA);
47 #endif 64 #endif
48 /* SSPCLK @ 120MHz 65 /* SSPCLK @ 96MHz
49 * gives bitrate of 120 / 100 / 3 = 400kHz */ 66 * gives bitrate of 96000 / 240 / 1 = 400kHz */
50 imx233_ssp_set_timings(MMC_SSP, 100, 2); 67 imx233_ssp_set_timings(MMC_SSP, 240, 0, 0xffff);
51 imx233_ssp_set_timeout(MMC_SSP, 0xffff);
52 imx233_ssp_sd_mmc_power_up_sequence(MMC_SSP); 68 imx233_ssp_sd_mmc_power_up_sequence(MMC_SSP);
69 imx233_ssp_set_bus_width(MMC_SSP, 1);
70 imx233_ssp_set_block_size(MMC_SSP, 9);
53 /* go to idle state */ 71 /* go to idle state */
54 int ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, SD_GO_IDLE_STATE, 0, SSP_NO_RESP, NULL, 0, false, NULL); 72 int ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, SD_GO_IDLE_STATE, 0, SSP_NO_RESP, NULL, 0, false, false, NULL);
55 if(ret != 0) 73 if(ret != 0)
56 return -1; 74 return -1;
57 /* send op cond until the card respond with busy bit set; it must complete within 1sec */ 75 /* send op cond until the card respond with busy bit set; it must complete within 1sec */
@@ -59,18 +77,82 @@ int mmc_init(void)
59 do 77 do
60 { 78 {
61 uint32_t ocr; 79 uint32_t ocr;
62 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 1, 0x40ff8000, SSP_SHORT_RESP, NULL, 0, false, &ocr); 80 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 1, 0x40ff8000, SSP_SHORT_RESP, NULL, 0, false, false, &ocr);
63 if(ret == 0 && ocr & (1 << 31)) 81 if(ret == 0 && ocr & (1 << 31))
64 break; 82 break;
65 }while(!TIME_AFTER(current_tick, timeout)); 83 }while(!TIME_AFTER(current_tick, timeout));
66 84
67 if(ret != 0) 85 if(ret != 0)
68 return -2; 86 return -2;
69 87 /* get CID */
70 uint32_t cid[4]; 88 uint32_t cid[4];
71 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 2, 0, SSP_LONG_RESP, NULL, 0, false, cid); 89 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 2, 0, SSP_LONG_RESP, NULL, 0, false, false, cid);
72 if(ret != 0) 90 if(ret != 0)
73 return -3; 91 return -3;
92 /* Set RCA */
93 uint32_t status;
94 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 3, MMC_RCA << 16, SSP_SHORT_RESP, NULL, 0, false, false, &status);
95 if(ret != 0)
96 return -4;
97 /* Select card */
98 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 7, MMC_RCA << 16, SSP_SHORT_RESP, NULL, 0, false, false, &status);
99 if(ret != 0)
100 return -5;
101 /* Check TRAN state */
102 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 13, MMC_RCA << 16, SSP_SHORT_RESP, NULL, 0, false, false, &status);
103 if(ret != 0)
104 return -6;
105 if(((status >> 9) & 0xf) != 4)
106 return -7;
107 /* Switch to 8-bit bus */
108 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 6, 0x3b70200, SSP_SHORT_RESP, NULL, 0, true, false, &status);
109 if(ret != 0)
110 return -8;
111 /* switch error ? */
112 if(status & 0x80)
113 return -9;
114 imx233_ssp_set_bus_width(MMC_SSP, 8);
115 /* Switch to high speed mode */
116 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 6, 0x3b90100, SSP_SHORT_RESP, NULL, 0, true, false, &status);
117 if(ret != 0)
118 return -10;
119 /* switch error ?*/
120 if(status & 0x80)
121 return -11;
122 /* SSPCLK @ 96MHz
123 * gives bitrate of 96 / 2 / 1 = 48MHz */
124 imx233_ssp_set_timings(MMC_SSP, 2, 0, 0xffff);
125
126 #ifdef SANSA_FUZEPLUS
127 /**
128 * The Fuze+ uses a strange layout: is has a first MBR at sector 0 with four entries:
129 * 1) Actual user partition
130 * 2) Sigmatel boot partition
131 * 3)4) Other (certificate related ?) partitions
132 * The partition 1) has type 1 but it's actually a type 5 (logical partition) with
133 * a second partition table with usually one entry which is the FAT32 one.
134 * The first table uses 512-byte sector size and the second one usually uses
135 * 2048-byte logical sector size.
136 *
137 * We restrict mmc window to the user partition */
138 uint8_t mbr[512];
139 mmc_window_start = 0;
140 mmc_window_end = INT_MAX;
141 ret = mmc_read_sectors(IF_MD2(0,) 0, 1, mbr);
142 if(ret != 0)
143 return -100;
144 if(mbr[510] != 0x55 || mbr[511] != 0xAA)
145 return -101; /* invalid MBR */
146 /* sanity check that the first partition is greater than 2Gib */
147 uint8_t *ent = &mbr[446];
148 mmc_window_start = ent[8] | ent[9] << 8 | ent[10] << 16 | ent[11] << 24;
149 mmc_window_end = (ent[12] | ent[13] << 8 | ent[14] << 16 | ent[15] << 24) +
150 mmc_window_start;
151 if(ent[4] == 0x53)
152 return -102; /* sigmatel partition */
153 if((mmc_window_end - mmc_window_start) < 4 * 1024 * 1024)
154 return -103; /* partition too small */
155 #endif
74 156
75 return 0; 157 return 0;
76} 158}
@@ -81,13 +163,49 @@ int mmc_num_drives(int first_drive)
81 return 1; 163 return 1;
82} 164}
83 165
84int mmc_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf) 166#ifdef STORAGE_GET_INFO
167void mmc_get_info(IF_MD2(int drive,) struct storage_info *info)
168{
169#ifdef HAVE_MULTIDRIVE
170 (void) drive;
171#endif
172 info->sector_size = 512;
173 info->num_sectors = 0xECC000 - 0x0001ac00;
174 info->vendor = "Rockbox";
175 info->product = "Internal Storage";
176 info->revision = "0.00";
177}
178#endif
179
180int mmc_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void *buf)
85{ 181{
86 IF_MD((void) drive); 182 IF_MD((void) drive);
87 (void) start; 183 /* check window */
88 (void) count; 184 start += mmc_window_start;
89 (void) buf; 185 if((start + count) > mmc_window_end)
90 return -1; 186 return -201;
187 /* get mutex (needed because we done multiple commands for count > 0 */
188 mutex_lock(&mmc_mutex);
189 int ret = 0;
190 uint32_t resp;
191
192 if(count == 1)
193 {
194 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 17, start, SSP_SHORT_RESP, buf,
195 count, false, true, &resp);
196 }
197 else
198 {
199 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 23, count, SSP_SHORT_RESP, NULL,
200 0, false, false, &resp);
201 if(ret == 0)
202 ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 18, start, SSP_SHORT_RESP, buf,
203 count, false, true, &resp);
204 }
205
206 mutex_unlock(&mmc_mutex);
207
208 return ret;
91} 209}
92 210
93int mmc_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf) 211int mmc_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf)