diff options
Diffstat (limited to 'firmware/target/arm/imx233/sd-imx233.c')
-rw-r--r-- | firmware/target/arm/imx233/sd-imx233.c | 324 |
1 files changed, 202 insertions, 122 deletions
diff --git a/firmware/target/arm/imx233/sd-imx233.c b/firmware/target/arm/imx233/sd-imx233.c index 1e9d001bbd..d3c29ee5be 100644 --- a/firmware/target/arm/imx233/sd-imx233.c +++ b/firmware/target/arm/imx233/sd-imx233.c | |||
@@ -24,62 +24,107 @@ | |||
24 | #include "sdmmc.h" | 24 | #include "sdmmc.h" |
25 | #include "ssp-imx233.h" | 25 | #include "ssp-imx233.h" |
26 | #include "pinctrl-imx233.h" | 26 | #include "pinctrl-imx233.h" |
27 | #include "partitions-imx233.h" | ||
27 | #include "button-target.h" | 28 | #include "button-target.h" |
28 | #include "fat.h" | 29 | #include "fat.h" |
29 | #include "disk.h" | 30 | #include "disk.h" |
30 | #include "usb.h" | 31 | #include "usb.h" |
31 | #include "debug.h" | 32 | #include "debug.h" |
32 | 33 | ||
33 | /** | 34 | struct sd_config_t |
34 | * This code assumes a single SD card slot | 35 | { |
35 | */ | 36 | const char *name; /* name(for debug) */ |
36 | 37 | int flags; /* flags */ | |
38 | int power_pin; /* power pin */ | ||
39 | int power_delay; /* extra power up delay */ | ||
40 | int ssp; /* associated ssp block */ | ||
41 | }; | ||
42 | |||
43 | /* flags */ | ||
44 | #define POWER_PIN (1 << 0) | ||
45 | #define POWER_INVERTED (1 << 1) | ||
46 | #define REMOVABLE (1 << 2) | ||
47 | #define DETECT_INVERTED (1 << 3) | ||
48 | #define POWER_DELAY (1 << 4) | ||
49 | #define WINDOW (1 << 5) | ||
50 | |||
51 | #define PIN(bank,pin) ((bank) << 5 | (pin)) | ||
52 | #define PIN2BANK(v) ((v) >> 5) | ||
53 | #define PIN2PIN(v) ((v) & 0x1f) | ||
54 | |||
55 | struct sd_config_t sd_config[] = | ||
56 | { | ||
37 | #ifdef SANSA_FUZEPLUS | 57 | #ifdef SANSA_FUZEPLUS |
38 | #define SD_SSP 1 | 58 | /* The Fuze+ uses pin #B0P8 for power */ |
59 | { | ||
60 | .name = "microSD", | ||
61 | .flags = POWER_PIN | POWER_INVERTED | REMOVABLE, | ||
62 | .power_pin = PIN(0, 8), | ||
63 | .ssp = 1 | ||
64 | }, | ||
39 | #else | 65 | #else |
40 | #error You need to configure the ssp to use | 66 | #error You need to write the sd config! |
41 | #endif | 67 | #endif |
68 | }; | ||
42 | 69 | ||
43 | static tCardInfo card_info; | 70 | #define SD_NUM_DRIVES (sizeof(sd_config) / sizeof(sd_config[0])) |
44 | static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)]; | 71 | |
72 | #define SD_CONF(drive) sd_config[drive] | ||
73 | #define SD_FLAGS(drive) SD_CONF(drive).flags | ||
74 | #define SD_SSP(drive) SD_CONF(drive).ssp | ||
75 | #define IF_FIRST_DRIVE(drive) if((drive) == 0) | ||
76 | #define IF_SECOND_DRIVE(drive) if((drive) == 1) | ||
77 | |||
78 | static tCardInfo card_info[SD_NUM_DRIVES]; | ||
79 | static long sd_stack[(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)]; | ||
45 | static struct mutex sd_mutex; | 80 | static struct mutex sd_mutex; |
46 | static const char sd_thread_name[] = "sd"; | 81 | static const char sd_thread_name[] = "sd"; |
47 | static struct event_queue sd_queue; | 82 | static struct event_queue sd_queue; |
48 | static int sd_first_drive; | 83 | static int sd_first_drive; |
49 | static int last_disk_activity; | 84 | static int last_disk_activity; |
85 | static unsigned sd_window_start[SD_NUM_DRIVES]; | ||
86 | static unsigned sd_window_end[SD_NUM_DRIVES]; | ||
50 | 87 | ||
51 | static void sd_detect_callback(int ssp) | 88 | static void sd_detect_callback(int ssp) |
52 | { | 89 | { |
53 | (void)ssp; | ||
54 | /* This is called only if the state was stable for 300ms - check state | 90 | /* This is called only if the state was stable for 300ms - check state |
55 | * and post appropriate event. */ | 91 | * and post appropriate event. */ |
56 | if(imx233_ssp_sdmmc_detect(SD_SSP)) | 92 | if(imx233_ssp_sdmmc_detect(ssp)) |
57 | queue_broadcast(SYS_HOTSWAP_INSERTED, 0); | 93 | queue_broadcast(SYS_HOTSWAP_INSERTED, 0); |
58 | else | 94 | else |
59 | queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); | 95 | queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); |
60 | imx233_ssp_sdmmc_setup_detect(SD_SSP, true, sd_detect_callback, false); | 96 | imx233_ssp_sdmmc_setup_detect(ssp, true, sd_detect_callback, false, |
97 | imx233_ssp_sdmmc_is_detect_inverted(ssp)); | ||
61 | } | 98 | } |
62 | 99 | ||
63 | void sd_power(bool on) | 100 | void sd_power(int drive, bool on) |
64 | { | 101 | { |
65 | #ifdef SANSA_FUZEPLUS | 102 | /* power chip if needed */ |
66 | /* The Fuze+ uses pin B0P8 for whatever reason, power ? */ | 103 | if(SD_FLAGS(drive) & POWER_PIN) |
67 | imx233_pinctrl_acquire_pin(0, 8, "sd power"); | 104 | { |
68 | imx233_set_pin_function(0, 8, PINCTRL_FUNCTION_GPIO); | 105 | int bank = PIN2BANK(SD_CONF(drive).power_pin); |
69 | imx233_enable_gpio_output(0, 8, true); | 106 | int pin = PIN2PIN(SD_CONF(drive).power_pin); |
70 | imx233_set_gpio_output(0, 8, !on); | 107 | imx233_pinctrl_acquire_pin(bank, pin, "sd power"); |
71 | /* disable pull ups when not needed to save power */ | 108 | imx233_set_pin_function(bank, pin, PINCTRL_FUNCTION_GPIO); |
72 | imx233_ssp_setup_ssp1_sd_mmc_pins(on, 4, PINCTRL_DRIVE_4mA, false); | 109 | imx233_enable_gpio_output(bank, pin, true); |
73 | #endif | 110 | if(SD_FLAGS(drive) & POWER_INVERTED) |
111 | imx233_set_gpio_output(bank, pin, !on); | ||
112 | else | ||
113 | imx233_set_gpio_output(bank, pin, on); | ||
114 | } | ||
115 | if(SD_FLAGS(drive) & POWER_DELAY) | ||
116 | sleep(SD_CONF(drive).power_delay); | ||
117 | /* setup pins, never use alternatives pin on SSP1 because these are force | ||
118 | * bus width >= 4 and SD cannot use more than 4 data lines. */ | ||
119 | if(SD_SSP(drive) == 1) | ||
120 | imx233_ssp_setup_ssp1_sd_mmc_pins(on, 4, PINCTRL_DRIVE_4mA, false); | ||
121 | else | ||
122 | imx233_ssp_setup_ssp2_sd_mmc_pins(on, 4, PINCTRL_DRIVE_4mA); | ||
74 | } | 123 | } |
75 | 124 | ||
76 | void sd_enable(bool on) | 125 | void sd_enable(bool on) |
77 | { | 126 | { |
78 | static int sd_enable = 2; /* 2 means not on and not off, for init purpose */ | 127 | (void) on; |
79 | if(sd_enable == on) | ||
80 | return; | ||
81 | |||
82 | sd_enable = on; | ||
83 | } | 128 | } |
84 | 129 | ||
85 | #define MCI_NO_RESP 0 | 130 | #define MCI_NO_RESP 0 |
@@ -89,15 +134,15 @@ void sd_enable(bool on) | |||
89 | #define MCI_NOCRC (1<<3) | 134 | #define MCI_NOCRC (1<<3) |
90 | #define MCI_BUSY (1<<4) | 135 | #define MCI_BUSY (1<<4) |
91 | 136 | ||
92 | static bool send_cmd(uint8_t cmd, uint32_t arg, uint32_t flags, uint32_t *resp) | 137 | static bool send_cmd(int drive, uint8_t cmd, uint32_t arg, uint32_t flags, uint32_t *resp) |
93 | { | 138 | { |
94 | if((flags & MCI_ACMD) && !send_cmd(SD_APP_CMD, card_info.rca, MCI_RESP, resp)) | 139 | if((flags & MCI_ACMD) && !send_cmd(drive, SD_APP_CMD, card_info[drive].rca, MCI_RESP, resp)) |
95 | return false; | 140 | return false; |
96 | 141 | ||
97 | enum imx233_ssp_resp_t resp_type = (flags & MCI_LONG_RESP) ? SSP_LONG_RESP : | 142 | enum imx233_ssp_resp_t resp_type = (flags & MCI_LONG_RESP) ? SSP_LONG_RESP : |
98 | (flags & MCI_RESP) ? SSP_SHORT_RESP : SSP_NO_RESP; | 143 | (flags & MCI_RESP) ? SSP_SHORT_RESP : SSP_NO_RESP; |
99 | enum imx233_ssp_error_t ret = imx233_ssp_sd_mmc_transfer(SD_SSP, cmd, arg, | 144 | enum imx233_ssp_error_t ret = imx233_ssp_sd_mmc_transfer(SD_SSP(drive), cmd, |
100 | resp_type, NULL, 0, !!(flags & MCI_BUSY), false, resp); | 145 | arg, resp_type, NULL, 0, !!(flags & MCI_BUSY), false, resp); |
101 | if(resp_type == SSP_LONG_RESP) | 146 | if(resp_type == SSP_LONG_RESP) |
102 | { | 147 | { |
103 | /* Our SD codes assume most significant word first, so reverse resp */ | 148 | /* Our SD codes assume most significant word first, so reverse resp */ |
@@ -111,7 +156,7 @@ static bool send_cmd(uint8_t cmd, uint32_t arg, uint32_t flags, uint32_t *resp) | |||
111 | return ret == SSP_SUCCESS; | 156 | return ret == SSP_SUCCESS; |
112 | } | 157 | } |
113 | 158 | ||
114 | static int sd_wait_for_tran_state(void) | 159 | static int sd_wait_for_tran_state(int drive) |
115 | { | 160 | { |
116 | unsigned long response; | 161 | unsigned long response; |
117 | unsigned int timeout = current_tick + 5*HZ; | 162 | unsigned int timeout = current_tick + 5*HZ; |
@@ -119,7 +164,7 @@ static int sd_wait_for_tran_state(void) | |||
119 | 164 | ||
120 | while (1) | 165 | while (1) |
121 | { | 166 | { |
122 | while(!send_cmd(SD_SEND_STATUS, card_info.rca, MCI_RESP, &response) && cmd_retry > 0) | 167 | while(!send_cmd(drive, SD_SEND_STATUS, card_info[drive].rca, MCI_RESP, &response) && cmd_retry > 0) |
123 | cmd_retry--; | 168 | cmd_retry--; |
124 | 169 | ||
125 | if(cmd_retry <= 0) | 170 | if(cmd_retry <= 0) |
@@ -135,33 +180,35 @@ static int sd_wait_for_tran_state(void) | |||
135 | } | 180 | } |
136 | } | 181 | } |
137 | 182 | ||
138 | static int sd_init_card(void) | 183 | static int sd_init_card(int drive) |
139 | { | 184 | { |
140 | sd_enable(false); | 185 | /* sanity check against bad configuration of SD_NUM_DRIVES/NUM_DRIVES */ |
141 | sd_power(false); | 186 | if((unsigned)drive >= SD_NUM_DRIVES) |
142 | sd_power(true); | 187 | panicf("drive >= SD_NUM_DRIVES in sd_init_card!"); |
143 | sd_enable(true); | 188 | int ssp = SD_SSP(drive); |
144 | imx233_ssp_start(SD_SSP); | 189 | sd_power(drive, false); |
145 | imx233_ssp_softreset(SD_SSP); | 190 | sd_power(drive, true); |
146 | imx233_ssp_set_mode(SD_SSP, HW_SSP_CTRL1__SSP_MODE__SD_MMC); | 191 | imx233_ssp_start(ssp); |
192 | imx233_ssp_softreset(ssp); | ||
193 | imx233_ssp_set_mode(ssp, HW_SSP_CTRL1__SSP_MODE__SD_MMC); | ||
147 | /* SSPCLK @ 96MHz | 194 | /* SSPCLK @ 96MHz |
148 | * gives bitrate of 96000 / 240 / 1 = 400kHz */ | 195 | * gives bitrate of 96000 / 240 / 1 = 400kHz */ |
149 | imx233_ssp_set_timings(SD_SSP, 240, 0, 0xffff); | 196 | imx233_ssp_set_timings(ssp, 240, 0, 0xffff); |
150 | 197 | ||
151 | imx233_ssp_sd_mmc_power_up_sequence(SD_SSP); | 198 | imx233_ssp_sd_mmc_power_up_sequence(ssp); |
152 | imx233_ssp_set_bus_width(SD_SSP, 1); | 199 | imx233_ssp_set_bus_width(ssp, 1); |
153 | imx233_ssp_set_block_size(SD_SSP, 9); | 200 | imx233_ssp_set_block_size(ssp, 9); |
154 | 201 | ||
155 | card_info.rca = 0; | 202 | card_info[drive].rca = 0; |
156 | bool sd_v2 = false; | 203 | bool sd_v2 = false; |
157 | uint32_t resp; | 204 | uint32_t resp; |
158 | long init_timeout; | 205 | long init_timeout; |
159 | /* go to idle state */ | 206 | /* go to idle state */ |
160 | if(!send_cmd(SD_GO_IDLE_STATE, 0, MCI_NO_RESP, NULL)) | 207 | if(!send_cmd(drive, SD_GO_IDLE_STATE, 0, MCI_NO_RESP, NULL)) |
161 | return -1; | 208 | return -1; |
162 | /* CMD8 Check for v2 sd card. Must be sent before using ACMD41 | 209 | /* CMD8 Check for v2 sd card. Must be sent before using ACMD41 |
163 | Non v2 cards will not respond to this command */ | 210 | Non v2 cards will not respond to this command */ |
164 | if(send_cmd(SD_SEND_IF_COND, 0x1AA, MCI_RESP, &resp)) | 211 | if(send_cmd(drive, SD_SEND_IF_COND, 0x1AA, MCI_RESP, &resp)) |
165 | if((resp & 0xFFF) == 0x1AA) | 212 | if((resp & 0xFFF) == 0x1AA) |
166 | sd_v2 = true; | 213 | sd_v2 = true; |
167 | /* timeout for initialization is 1sec, from SD Specification 2.00 */ | 214 | /* timeout for initialization is 1sec, from SD Specification 2.00 */ |
@@ -173,67 +220,84 @@ static int sd_init_card(void) | |||
173 | return -2; | 220 | return -2; |
174 | 221 | ||
175 | /* ACMD41 For v2 cards set HCS bit[30] & send host voltage range to all */ | 222 | /* ACMD41 For v2 cards set HCS bit[30] & send host voltage range to all */ |
176 | if(!send_cmd(SD_APP_OP_COND, (0x00FF8000 | (sd_v2 ? 1<<30 : 0)), | 223 | if(!send_cmd(drive, SD_APP_OP_COND, (0x00FF8000 | (sd_v2 ? 1<<30 : 0)), |
177 | MCI_ACMD|MCI_NOCRC|MCI_RESP, &card_info.ocr)) | 224 | MCI_ACMD|MCI_NOCRC|MCI_RESP, &card_info[drive].ocr)) |
178 | return -100; | 225 | return -100; |
179 | } while(!(card_info.ocr & (1<<31))); | 226 | } while(!(card_info[drive].ocr & (1<<31))); |
180 | 227 | ||
181 | /* CMD2 send CID */ | 228 | /* CMD2 send CID */ |
182 | if(!send_cmd(SD_ALL_SEND_CID, 0, MCI_RESP|MCI_LONG_RESP, card_info.cid)) | 229 | if(!send_cmd(drive, SD_ALL_SEND_CID, 0, MCI_RESP|MCI_LONG_RESP, card_info[drive].cid)) |
183 | return -3; | 230 | return -3; |
184 | 231 | ||
185 | /* CMD3 send RCA */ | 232 | /* CMD3 send RCA */ |
186 | if(!send_cmd(SD_SEND_RELATIVE_ADDR, 0, MCI_RESP, &card_info.rca)) | 233 | if(!send_cmd(drive, SD_SEND_RELATIVE_ADDR, 0, MCI_RESP, &card_info[drive].rca)) |
187 | return -4; | 234 | return -4; |
188 | 235 | ||
189 | /* Try to switch V2 cards to HS timings, non HS seem to ignore this */ | 236 | /* Try to switch V2 cards to HS timings, non HS seem to ignore this */ |
190 | if(sd_v2) | 237 | if(sd_v2) |
191 | { | 238 | { |
192 | /* CMD7 w/rca: Select card to put it in TRAN state */ | 239 | /* CMD7 w/rca: Select card to put it in TRAN state */ |
193 | if(!send_cmd(SD_SELECT_CARD, card_info.rca, MCI_RESP, NULL)) | 240 | if(!send_cmd(drive, SD_SELECT_CARD, card_info[drive].rca, MCI_RESP, NULL)) |
194 | return -5; | 241 | return -5; |
195 | 242 | ||
196 | if(sd_wait_for_tran_state()) | 243 | if(sd_wait_for_tran_state(drive)) |
197 | return -6; | 244 | return -6; |
198 | 245 | ||
199 | /* CMD6 */ | 246 | /* CMD6 */ |
200 | if(!send_cmd(SD_SWITCH_FUNC, 0x80fffff1, MCI_NO_RESP, NULL)) | 247 | if(!send_cmd(drive, SD_SWITCH_FUNC, 0x80fffff1, MCI_NO_RESP, NULL)) |
201 | return -7; | 248 | return -7; |
202 | sleep(HZ/10); | 249 | sleep(HZ/10); |
203 | 250 | ||
204 | /* go back to STBY state so we can read csd */ | 251 | /* go back to STBY state so we can read csd */ |
205 | /* CMD7 w/rca=0: Deselect card to put it in STBY state */ | 252 | /* CMD7 w/rca=0: Deselect card to put it in STBY state */ |
206 | if(!send_cmd(SD_DESELECT_CARD, 0, MCI_NO_RESP, NULL)) | 253 | if(!send_cmd(drive, SD_DESELECT_CARD, 0, MCI_NO_RESP, NULL)) |
207 | return -8; | 254 | return -8; |
208 | } | 255 | } |
209 | 256 | ||
210 | /* CMD9 send CSD */ | 257 | /* CMD9 send CSD */ |
211 | if(!send_cmd(SD_SEND_CSD, card_info.rca, MCI_RESP|MCI_LONG_RESP, card_info.csd)) | 258 | if(!send_cmd(drive, SD_SEND_CSD, card_info[drive].rca, MCI_RESP|MCI_LONG_RESP, card_info[drive].csd)) |
212 | return -9; | 259 | return -9; |
213 | 260 | ||
214 | sd_parse_csd(&card_info); | 261 | sd_parse_csd(&card_info[drive]); |
215 | 262 | ||
216 | /* SSPCLK @ 96MHz | 263 | /* SSPCLK @ 96MHz |
217 | * gives bitrate of 96 / 4 / 1 = 24MHz */ | 264 | * gives bitrate of 96 / 4 / 1 = 24MHz */ |
218 | imx233_ssp_set_timings(SD_SSP, 4, 0, 0xffff); | 265 | imx233_ssp_set_timings(ssp, 4, 0, 0xffff); |
219 | 266 | ||
220 | /* CMD7 w/rca: Select card to put it in TRAN state */ | 267 | /* CMD7 w/rca: Select card to put it in TRAN state */ |
221 | if(!send_cmd(SD_SELECT_CARD, card_info.rca, MCI_RESP, &resp)) | 268 | if(!send_cmd(drive, SD_SELECT_CARD, card_info[drive].rca, MCI_RESP, &resp)) |
222 | return -12; | 269 | return -12; |
223 | if(sd_wait_for_tran_state() < 0) | 270 | if(sd_wait_for_tran_state(drive) < 0) |
224 | return -13; | 271 | return -13; |
225 | 272 | ||
226 | /* ACMD6: set bus width to 4-bit */ | 273 | /* ACMD6: set bus width to 4-bit */ |
227 | if(!send_cmd(SD_SET_BUS_WIDTH, 2, MCI_RESP|MCI_ACMD, &resp)) | 274 | if(!send_cmd(drive, SD_SET_BUS_WIDTH, 2, MCI_RESP|MCI_ACMD, &resp)) |
228 | return -15; | 275 | return -15; |
229 | /* ACMD42: disconnect the pull-up resistor on CD/DAT3 */ | 276 | /* ACMD42: disconnect the pull-up resistor on CD/DAT3 */ |
230 | if(!send_cmd(SD_SET_CLR_CARD_DETECT, 0, MCI_RESP|MCI_ACMD, &resp)) | 277 | if(!send_cmd(drive, SD_SET_CLR_CARD_DETECT, 0, MCI_RESP|MCI_ACMD, &resp)) |
231 | return -17; | 278 | return -17; |
232 | 279 | ||
233 | /* Switch to 4-bit */ | 280 | /* Switch to 4-bit */ |
234 | imx233_ssp_set_bus_width(SD_SSP, 4); | 281 | imx233_ssp_set_bus_width(ssp, 4); |
235 | 282 | ||
236 | card_info.initialized = 1; | 283 | card_info[drive].initialized = 1; |
284 | |||
285 | /* compute window */ | ||
286 | sd_window_start[drive] = 0; | ||
287 | sd_window_end[drive] = card_info[drive].numblocks; | ||
288 | if((SD_FLAGS(drive) & WINDOW) && imx233_partitions_is_window_enabled()) | ||
289 | { | ||
290 | /* WARNING: sd_first_drive is not set at this point */ | ||
291 | uint8_t mbr[512]; | ||
292 | int ret = sd_read_sectors(IF_MD2(drive,) 0, 1, mbr); | ||
293 | if(ret) | ||
294 | panicf("Cannot read MBR: %d", ret); | ||
295 | ret = imx233_partitions_compute_window(mbr, &sd_window_start[drive], | ||
296 | &sd_window_end[drive]); | ||
297 | if(ret) | ||
298 | panicf("cannot compute partitions window: %d", ret); | ||
299 | card_info[drive].numblocks = sd_window_end[drive] - sd_window_start[drive]; | ||
300 | } | ||
237 | 301 | ||
238 | return 0; | 302 | return 0; |
239 | } | 303 | } |
@@ -253,45 +317,51 @@ static void sd_thread(void) | |||
253 | case SYS_HOTSWAP_EXTRACTED: | 317 | case SYS_HOTSWAP_EXTRACTED: |
254 | { | 318 | { |
255 | int microsd_init = 1; | 319 | int microsd_init = 1; |
256 | fat_lock(); /* lock-out FAT activity first - | 320 | /* lock-out FAT activity first - |
257 | prevent deadlocking via disk_mount that | 321 | * prevent deadlocking via disk_mount that |
258 | would cause a reverse-order attempt with | 322 | * would cause a reverse-order attempt with |
259 | another thread */ | 323 | * another thread */ |
260 | mutex_lock(&sd_mutex); /* lock-out card activity - direct calls | 324 | fat_lock(); |
261 | into driver that bypass the fat cache */ | 325 | /* lock-out card activity - direct calls |
262 | 326 | * into driver that bypass the fat cache */ | |
263 | /* We now have exclusive control of fat cache and sd */ | 327 | mutex_lock(&sd_mutex); |
264 | 328 | ||
265 | disk_unmount(sd_first_drive); /* release "by force", ensure file | 329 | /* We now have exclusive control of fat cache and sd. |
266 | descriptors aren't leaked and any busy | 330 | * Release "by force", ensure file |
267 | ones are invalid if mounting */ | 331 | * descriptors aren't leaked and any busy |
268 | /* Force card init for new card, re-init for re-inserted one or | 332 | * ones are invalid if mounting. */ |
269 | * clear if the last attempt to init failed with an error. */ | 333 | for(unsigned drive = 0; drive < SD_NUM_DRIVES; drive++) |
270 | card_info.initialized = 0; | ||
271 | |||
272 | if(ev.id == SYS_HOTSWAP_INSERTED) | ||
273 | { | 334 | { |
274 | microsd_init = sd_init_card(); | 335 | /* Skip non-removable drivers */ |
275 | if(microsd_init < 0) /* initialisation failed */ | 336 | if(!sd_removable(drive)) |
276 | panicf("microSD init failed : %d", microsd_init); | 337 | continue; |
277 | 338 | disk_unmount(sd_first_drive + drive); | |
278 | microsd_init = disk_mount(sd_first_drive); /* 0 if fail */ | 339 | /* Force card init for new card, re-init for re-inserted one or |
340 | * clear if the last attempt to init failed with an error. */ | ||
341 | card_info[drive].initialized = 0; | ||
342 | |||
343 | if(ev.id == SYS_HOTSWAP_INSERTED) | ||
344 | { | ||
345 | microsd_init = sd_init_card(drive); | ||
346 | if(microsd_init < 0) /* initialisation failed */ | ||
347 | panicf("%s init failed : %d", SD_CONF(drive).name, microsd_init); | ||
348 | |||
349 | microsd_init = disk_mount(sd_first_drive + drive); /* 0 if fail */ | ||
350 | } | ||
351 | /* | ||
352 | * Mount succeeded, or this was an EXTRACTED event, | ||
353 | * in both cases notify the system about the changed filesystems | ||
354 | */ | ||
355 | if(microsd_init) | ||
356 | queue_broadcast(SYS_FS_CHANGED, 0); | ||
279 | } | 357 | } |
280 | /* | ||
281 | * Mount succeeded, or this was an EXTRACTED event, | ||
282 | * in both cases notify the system about the changed filesystems | ||
283 | */ | ||
284 | if(microsd_init) | ||
285 | queue_broadcast(SYS_FS_CHANGED, 0); | ||
286 | |||
287 | sd_enable(false); | ||
288 | /* Access is now safe */ | 358 | /* Access is now safe */ |
289 | mutex_unlock(&sd_mutex); | 359 | mutex_unlock(&sd_mutex); |
290 | fat_unlock(); | 360 | fat_unlock(); |
291 | break; | 361 | break; |
292 | } | 362 | } |
293 | case SYS_TIMEOUT: | 363 | case SYS_TIMEOUT: |
294 | if(!TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) | 364 | if(!TIME_BEFORE(current_tick, last_disk_activity +3 * HZ)) |
295 | sd_enable(false); | 365 | sd_enable(false); |
296 | break; | 366 | break; |
297 | case SYS_USB_CONNECTED: | 367 | case SYS_USB_CONNECTED: |
@@ -309,8 +379,13 @@ int sd_init(void) | |||
309 | queue_init(&sd_queue, true); | 379 | queue_init(&sd_queue, true); |
310 | create_thread(sd_thread, sd_stack, sizeof(sd_stack), 0, | 380 | create_thread(sd_thread, sd_stack, sizeof(sd_stack), 0, |
311 | sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); | 381 | sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); |
312 | sd_enable(false); | 382 | |
313 | imx233_ssp_sdmmc_setup_detect(SD_SSP, true, sd_detect_callback, false); | 383 | for(unsigned drive = 0; drive < SD_NUM_DRIVES; drive++) |
384 | { | ||
385 | if(SD_FLAGS(drive) & REMOVABLE) | ||
386 | imx233_ssp_sdmmc_setup_detect(SD_SSP(drive), true, sd_detect_callback, | ||
387 | false, SD_FLAGS(drive) & DETECT_INVERTED); | ||
388 | } | ||
314 | 389 | ||
315 | return 0; | 390 | return 0; |
316 | } | 391 | } |
@@ -324,21 +399,28 @@ static int transfer_sectors(IF_MD2(int drive,) unsigned long start, int count, v | |||
324 | last_disk_activity = current_tick; | 399 | last_disk_activity = current_tick; |
325 | 400 | ||
326 | mutex_lock(&sd_mutex); | 401 | mutex_lock(&sd_mutex); |
327 | sd_enable(true); | ||
328 | 402 | ||
329 | if(card_info.initialized <= 0) | 403 | if(card_info[drive].initialized <= 0) |
330 | { | 404 | { |
331 | ret = sd_init_card(); | 405 | ret = sd_init_card(drive); |
332 | if(card_info.initialized <= 0) | 406 | if(card_info[drive].initialized <= 0) |
333 | goto Lend; | 407 | goto Lend; |
334 | } | 408 | } |
409 | |||
410 | /* check window */ | ||
411 | start += sd_window_start[drive]; | ||
412 | if((start + count) > sd_window_end[drive]) | ||
413 | { | ||
414 | ret = -201; | ||
415 | goto Lend; | ||
416 | } | ||
335 | 417 | ||
336 | if(!send_cmd(SD_SELECT_CARD, card_info.rca, MCI_NO_RESP, NULL)) | 418 | if(!send_cmd(drive, SD_SELECT_CARD, card_info[drive].rca, MCI_NO_RESP, NULL)) |
337 | { | 419 | { |
338 | ret = -20; | 420 | ret = -20; |
339 | goto Lend; | 421 | goto Lend; |
340 | } | 422 | } |
341 | ret = sd_wait_for_tran_state(); | 423 | ret = sd_wait_for_tran_state(drive); |
342 | if(ret < 0) | 424 | if(ret < 0) |
343 | goto Ldeselect; | 425 | goto Ldeselect; |
344 | while(count != 0) | 426 | while(count != 0) |
@@ -346,13 +428,14 @@ static int transfer_sectors(IF_MD2(int drive,) unsigned long start, int count, v | |||
346 | int this_count = MIN(count, IMX233_MAX_SSP_XFER_SIZE / 512); | 428 | int this_count = MIN(count, IMX233_MAX_SSP_XFER_SIZE / 512); |
347 | /* Set bank_start to the correct unit (blocks or bytes) */ | 429 | /* Set bank_start to the correct unit (blocks or bytes) */ |
348 | int bank_start = start; | 430 | int bank_start = start; |
349 | if(!(card_info.ocr & (1<<30))) /* not SDHC */ | 431 | if(!(card_info[drive].ocr & (1<<30))) /* not SDHC */ |
350 | bank_start *= SD_BLOCK_SIZE; | 432 | bank_start *= SD_BLOCK_SIZE; |
351 | ret = imx233_ssp_sd_mmc_transfer(SD_SSP, read ? SD_READ_MULTIPLE_BLOCK : SD_WRITE_MULTIPLE_BLOCK, | 433 | ret = imx233_ssp_sd_mmc_transfer(SD_SSP(drive), |
434 | read ? SD_READ_MULTIPLE_BLOCK : SD_WRITE_MULTIPLE_BLOCK, | ||
352 | bank_start, SSP_SHORT_RESP, buf, this_count, false, read, &resp); | 435 | bank_start, SSP_SHORT_RESP, buf, this_count, false, read, &resp); |
353 | if(ret != SSP_SUCCESS) | 436 | if(ret != SSP_SUCCESS) |
354 | break; | 437 | break; |
355 | if(!send_cmd(SD_STOP_TRANSMISSION, 0, MCI_RESP|MCI_BUSY, &resp)) | 438 | if(!send_cmd(drive, SD_STOP_TRANSMISSION, 0, MCI_RESP|MCI_BUSY, &resp)) |
356 | { | 439 | { |
357 | ret = -15; | 440 | ret = -15; |
358 | break; | 441 | break; |
@@ -364,51 +447,48 @@ static int transfer_sectors(IF_MD2(int drive,) unsigned long start, int count, v | |||
364 | 447 | ||
365 | Ldeselect: | 448 | Ldeselect: |
366 | /* CMD7 w/rca =0 : deselects card & puts it in STBY state */ | 449 | /* CMD7 w/rca =0 : deselects card & puts it in STBY state */ |
367 | if(!send_cmd(SD_DESELECT_CARD, 0, MCI_NO_RESP, NULL)) | 450 | if(!send_cmd(drive, SD_DESELECT_CARD, 0, MCI_NO_RESP, NULL)) |
368 | ret = -23; | 451 | ret = -23; |
369 | Lend: | 452 | Lend: |
370 | mutex_unlock(&sd_mutex); | 453 | mutex_unlock(&sd_mutex); |
371 | return ret; | 454 | return ret; |
372 | } | 455 | } |
373 | 456 | ||
374 | int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count, | 457 | int sd_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf) |
375 | void* buf) | ||
376 | { | 458 | { |
377 | return transfer_sectors(IF_MD2(drive,) start, count, buf, true); | 459 | return transfer_sectors(IF_MD2(drive,) start, count, buf, true); |
378 | } | 460 | } |
379 | 461 | ||
380 | int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count, | 462 | int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf) |
381 | const void* buf) | ||
382 | { | 463 | { |
383 | return transfer_sectors(IF_MD2(drive,) start, count, (void *)buf, false); | 464 | return transfer_sectors(IF_MD2(drive,) start, count, (void *)buf, false); |
384 | } | 465 | } |
385 | 466 | ||
386 | tCardInfo *card_get_info_target(int card_no) | 467 | tCardInfo *card_get_info_target(int card_no) |
387 | { | 468 | { |
388 | (void)card_no; | 469 | return &card_info[card_no]; |
389 | return &card_info; | ||
390 | } | 470 | } |
391 | 471 | ||
392 | int sd_num_drives(int first_drive) | 472 | int sd_num_drives(int first_drive) |
393 | { | 473 | { |
394 | sd_first_drive = first_drive; | 474 | sd_first_drive = first_drive; |
395 | return 1; | 475 | return SD_NUM_DRIVES; |
396 | } | 476 | } |
397 | 477 | ||
398 | bool sd_present(IF_MD(int drive)) | 478 | bool sd_present(IF_MV_NONVOID(int drive)) |
399 | { | 479 | { |
400 | IF_MD((void) drive); | 480 | if(SD_FLAGS(drive) & REMOVABLE) |
401 | return imx233_ssp_sdmmc_detect(SD_SSP); | 481 | return imx233_ssp_sdmmc_detect(SD_SSP(drive)); |
482 | else | ||
483 | return true; | ||
402 | } | 484 | } |
403 | 485 | ||
404 | bool sd_removable(IF_MD(int drive)) | 486 | bool sd_removable(IF_MV_NONVOID(int drive)) |
405 | { | 487 | { |
406 | IF_MD((void) drive); | 488 | return SD_FLAGS(drive) & REMOVABLE; |
407 | return true; | ||
408 | } | 489 | } |
409 | 490 | ||
410 | long sd_last_disk_activity(void) | 491 | long sd_last_disk_activity(void) |
411 | { | 492 | { |
412 | return last_disk_activity; | 493 | return last_disk_activity; |
413 | } | 494 | } |
414 | |||