summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/as3525/app.lds126
-rw-r--r--firmware/target/arm/as3525/ata_sd_as3525.c590
-rw-r--r--firmware/target/arm/as3525/kernel-as3525.c6
-rw-r--r--firmware/target/arm/as3525/sansa-clip/system-target.h4
-rw-r--r--firmware/target/arm/as3525/system-as3525.c17
5 files changed, 595 insertions, 148 deletions
diff --git a/firmware/target/arm/as3525/app.lds b/firmware/target/arm/as3525/app.lds
new file mode 100644
index 0000000000..08b119eb3f
--- /dev/null
+++ b/firmware/target/arm/as3525/app.lds
@@ -0,0 +1,126 @@
1#include "config.h"
2
3ENTRY(start)
4
5OUTPUT_FORMAT(elf32-littlearm)
6OUTPUT_ARCH(arm)
7STARTUP(target/arm/crt0.o)
8
9#define PLUGINSIZE PLUGIN_BUFFER_SIZE
10#define CODECSIZE CODEC_SIZE
11
12#ifdef DEBUG
13#define STUBOFFSET 0x10000
14#else
15#define STUBOFFSET 0
16#endif
17
18#include "cpu.h"
19#define IRAMSIZE 0x50000
20#define DRAMSIZE (MEMORYSIZE * 0x100000) - STUBOFFSET - PLUGINSIZE - CODECSIZE
21
22#define IRAMORIG 0x0
23#define DRAMORIG 0x30000000 + STUBOFFSET
24
25/* End of the audio buffer, where the codec buffer starts */
26#define ENDAUDIOADDR (DRAMORIG + DRAMSIZE)
27
28/* Where the codec buffer ends, and the plugin buffer starts */
29#define ENDADDR (ENDAUDIOADDR + CODECSIZE)
30
31MEMORY
32{
33 IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE
34 DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE
35}
36
37SECTIONS
38{
39 loadaddress = 0x30000000;
40
41 .vectors DRAMORIG :
42 {
43 _vectorstart = .;
44 *(.vectors*);
45 *(.init.text)
46 . = ALIGN(0x4);
47 } > DRAM
48
49 .text :
50 {
51 _textstart = .;
52 *(.text)
53 *(.text*)
54 *(.icode)
55 *(.glue_7)
56 *(.glue_7t)
57 . = ALIGN(0x4);
58 } > DRAM
59
60 .rodata :
61 {
62 *(.rodata) /* problems without this, dunno why */
63 *(.rodata*)
64 *(.rodata.str1.1)
65 *(.rodata.str1.4)
66 *(.irodata*)
67 . = ALIGN(0x4);
68 } > DRAM
69
70 .data :
71 {
72 *(.data*)
73 *(.idata*)
74 . = ALIGN(0x4);
75 } > DRAM
76
77 /DISCARD/ :
78 {
79 *(.eh_frame)
80 }
81
82 _initdata_end =.;
83
84 .stack (NOLOAD) :
85 {
86 *(.stack)
87 stackbegin = .;
88 . += 0x2000;
89 stackend = .;
90 } > DRAM
91
92 .bss (NOLOAD) :
93 {
94 _edata = .;
95 *(.bss*)
96 *(.ibss*)
97 *(COMMON)
98 . = ALIGN(0x4);
99 _end = .;
100 } > DRAM
101
102 .audiobuf (NOLOAD) :
103 {
104 . = ALIGN(4);
105 _audiobuffer = .;
106 audiobuffer = .;
107 } > DRAM
108
109 .audiobufend ENDAUDIOADDR (NOLOAD) :
110 {
111 audiobufend = .;
112 _audiobufend = .;
113 } > DRAM
114
115 .codec ENDAUDIOADDR (NOLOAD) :
116 {
117 codecbuf = .;
118 _codecbuf = .;
119 }
120
121 .plugin ENDADDR (NOLOAD) :
122 {
123 _pluginbuf = .;
124 pluginbuf = .;
125 }
126}
diff --git a/firmware/target/arm/as3525/ata_sd_as3525.c b/firmware/target/arm/as3525/ata_sd_as3525.c
index 77d1ec1504..18cbb139e0 100644
--- a/firmware/target/arm/as3525/ata_sd_as3525.c
+++ b/firmware/target/arm/as3525/ata_sd_as3525.c
@@ -7,6 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2006 Daniel Ankers
10 * Copyright © 2008 Rafaël Carré 11 * Copyright © 2008 Rafaël Carré
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
@@ -22,19 +23,31 @@
22/* Driver for the ARM PL180 SD/MMC controller inside AS3525 SoC */ 23/* Driver for the ARM PL180 SD/MMC controller inside AS3525 SoC */
23 24
24#include "config.h" /* for HAVE_MULTIVOLUME */ 25#include "config.h" /* for HAVE_MULTIVOLUME */
25 26#include "fat.h"
27#include "thread.h"
28#include "hotswap.h"
29#include "system.h"
30#include "cpu.h"
31#include <stdlib.h>
26#include "as3525.h" 32#include "as3525.h"
27#include "pl180.h" 33#include "pl180.h"
28#include "panic.h" 34#include "panic.h"
29#include "stdbool.h" 35#include "stdbool.h"
36#include "ata_idle_notify.h"
30#include "sd.h" 37#include "sd.h"
31 38
32#define NAND_AS3525 0 39#ifdef HAVE_HOTSWAP
33#define SD_AS3525 1 40#include "disk.h"
34static const int pl180_base[2] = { NAND_FLASH_BASE, SD_MCI_BASE }; 41#endif
42
43/* command flags */
44#define MMC_NO_FLAGS (0<<0)
45#define MMC_RESP (1<<0)
46#define MMC_LONG_RESP (1<<1)
47#define MMC_ARG (1<<2)
35 48
36/* ARM PL180 registers */ 49/* ARM PL180 registers */
37#define MMC_POWER(i) (*(volatile unsigned long *) (pl180_base[i]+0x00)) 50#define MMC_POWER(i) (*(volatile unsigned char *) (pl180_base[i]+0x00))
38#define MMC_CLOCK(i) (*(volatile unsigned long *) (pl180_base[i]+0x04)) 51#define MMC_CLOCK(i) (*(volatile unsigned long *) (pl180_base[i]+0x04))
39#define MMC_ARGUMENT(i) (*(volatile unsigned long *) (pl180_base[i]+0x08)) 52#define MMC_ARGUMENT(i) (*(volatile unsigned long *) (pl180_base[i]+0x08))
40#define MMC_COMMAND(i) (*(volatile unsigned long *) (pl180_base[i]+0x0C)) 53#define MMC_COMMAND(i) (*(volatile unsigned long *) (pl180_base[i]+0x0C))
@@ -43,40 +56,45 @@ static const int pl180_base[2] = { NAND_FLASH_BASE, SD_MCI_BASE };
43#define MMC_RESP1(i) (*(volatile unsigned long *) (pl180_base[i]+0x18)) 56#define MMC_RESP1(i) (*(volatile unsigned long *) (pl180_base[i]+0x18))
44#define MMC_RESP2(i) (*(volatile unsigned long *) (pl180_base[i]+0x1C)) 57#define MMC_RESP2(i) (*(volatile unsigned long *) (pl180_base[i]+0x1C))
45#define MMC_RESP3(i) (*(volatile unsigned long *) (pl180_base[i]+0x20)) 58#define MMC_RESP3(i) (*(volatile unsigned long *) (pl180_base[i]+0x20))
46#define MMC_DATACTRL(i) (*(volatile unsigned long *) (pl180_base[i]+0x2C)) 59#define MMC_DATA_TIMER(i) (*(volatile unsigned long *) (pl180_base[i]+0x24))
60#define MMC_DATA_LENGTH(i) (*(volatile unsigned short*) (pl180_base[i]+0x28))
61#define MMC_DATA_CTRL(i) (*(volatile unsigned char *) (pl180_base[i]+0x2C))
62#define MMC_DATA_CNT(i) (*(volatile unsigned short*) (pl180_base[i]+0x30))
47#define MMC_STATUS(i) (*(volatile unsigned long *) (pl180_base[i]+0x34)) 63#define MMC_STATUS(i) (*(volatile unsigned long *) (pl180_base[i]+0x34))
48#define MMC_CLEAR(i) (*(volatile unsigned long *) (pl180_base[i]+0x38)) 64#define MMC_CLEAR(i) (*(volatile unsigned long *) (pl180_base[i]+0x38))
49#define MMC_MASK0(i) (*(volatile unsigned long *) (pl180_base[i]+0x3C)) 65#define MMC_MASK0(i) (*(volatile unsigned long *) (pl180_base[i]+0x3C))
50#define MMC_MASK1(i) (*(volatile unsigned long *) (pl180_base[i]+0x40)) 66#define MMC_MASK1(i) (*(volatile unsigned long *) (pl180_base[i]+0x40))
51#define MMC_SELECT(i) (*(volatile unsigned long *) (pl180_base[i]+0x44)) 67#define MMC_SELECT(i) (*(volatile unsigned long *) (pl180_base[i]+0x44))
68#define MMC_FIFO_CNT(i) (*(volatile unsigned long *) (pl180_base[i]+0x48))
52 69
70#define MMC_FIFO(i) ((unsigned long *) (pl180_base[i]+0x80))
71/* volumes */
72#define NAND_AS3525 0
73#define SD_AS3525 1
53 74
54/* SD commands */ 75static const int pl180_base[NUM_VOLUMES] = {
55#define GO_IDLE_STATE 0 76 NAND_FLASH_BASE
56#define MMC_CMD_READ_CID 2 77#ifdef HAVE_MULTIVOLUME
57#define SEND_IF_COND 8 78 , SD_MCI_BASE
58#define SEND_OP_COND 41 79#endif
59#define APP_CMD 55 80};
60 81
61/* command flags */ 82#define BLOCK_SIZE 512
62#define MMC_NO_FLAGS (0<<0) 83#define SECTOR_SIZE 512
63#define MMC_RESP (1<<0)
64#define MMC_LONG_RESP (1<<1)
65#define MMC_ARG (1<<2)
66 84
67#ifdef BOOTLOADER 85static tSDCardInfo card_info[NUM_VOLUMES];
68#define DEBUG
69void reset_screen(void);
70void printf(const char *format, ...);
71#endif
72 86
73struct mmc_command 87/* for compatibility */
74{ 88static long last_disk_activity = -1;
75 int cmd; 89
76 int arg; 90#define MIN_YIELD_PERIOD 1000
77 int resp[4]; 91static long next_yield = 0;
78 int flags; 92
79}; 93/* Shoot for around 75% usage */
94static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)];
95static const char sd_thread_name[] = "ata/sd";
96static struct mutex sd_mtx SHAREDBSS_ATTR;
97static struct event_queue sd_queue;
80 98
81static inline void mci_delay(void) { int i = 0xffff; while(i--) ; } 99static inline void mci_delay(void) { int i = 0xffff; while(i--) ; }
82 100
@@ -106,11 +124,12 @@ static void mci_set_clock_divider(const int drive, int divider)
106 mci_delay(); 124 mci_delay();
107} 125}
108 126
109static int send_cmd(const int drive, struct mmc_command *cmd) 127static bool send_cmd(const int drive, const int cmd, const int arg,
128 const int flags, int *response)
110{ 129{
111 int val, status; 130 int val, status;
112 131
113 while(MMC_STATUS(drive) & MCI_CMD_ACTIVE); /* useless */ 132 while(MMC_STATUS(drive) & MCI_CMD_ACTIVE);
114 133
115 if(MMC_COMMAND(drive) & MCI_COMMAND_ENABLE) /* clears existing command */ 134 if(MMC_COMMAND(drive) & MCI_COMMAND_ENABLE) /* clears existing command */
116 { 135 {
@@ -118,152 +137,226 @@ static int send_cmd(const int drive, struct mmc_command *cmd)
118 mci_delay(); 137 mci_delay();
119 } 138 }
120 139
121 val = cmd->cmd | MCI_COMMAND_ENABLE; 140 val = cmd | MCI_COMMAND_ENABLE;
122 if(cmd->flags & MMC_RESP) 141 if(flags & MMC_RESP)
123 { 142 {
124 val |= MCI_COMMAND_RESPONSE; 143 val |= MCI_COMMAND_RESPONSE;
125 if(cmd->flags & MMC_LONG_RESP) 144 if(flags & MMC_LONG_RESP)
126 val |= MCI_COMMAND_LONG_RESPONSE; 145 val |= MCI_COMMAND_LONG_RESPONSE;
127 } 146 }
128 147
129 MMC_CLEAR(drive) = 0x7ff; 148 MMC_CLEAR(drive) = 0x7ff;
130 149
131 MMC_ARGUMENT(drive) = (cmd->flags & MMC_ARG) ? cmd->arg : 0; 150 MMC_ARGUMENT(drive) = (flags & MMC_ARG) ? arg : 0;
132 MMC_COMMAND(drive) = val; 151 MMC_COMMAND(drive) = val;
133 152
134 while(MMC_STATUS(drive) & MCI_CMD_ACTIVE); 153 while(MMC_STATUS(drive) & MCI_CMD_ACTIVE); /* wait for cmd completion */
135 154
136 MMC_COMMAND(drive) = 0; 155 MMC_COMMAND(drive) = 0;
137 MMC_ARGUMENT(drive) = ~0; 156 MMC_ARGUMENT(drive) = ~0;
138 157
139 do 158 status = MMC_STATUS(drive);
159 MMC_CLEAR(drive) = 0x7ff;
160
161 if(flags & MMC_RESP)
140 { 162 {
141 status = MMC_STATUS(drive); 163 if(status & MCI_CMD_TIMEOUT)
142 if(cmd->flags & MMC_RESP) 164 return false;
143 { 165 else if(status & (MCI_CMD_CRC_FAIL /* FIXME? */ | MCI_CMD_RESP_END))
144 if(status & MCI_CMD_TIMEOUT) 166 { /* resp received */
167 if(flags & MMC_LONG_RESP)
145 { 168 {
146 if(cmd->cmd == SEND_IF_COND) 169 /* store the response in little endian order for the words */
147 break; /* SDHC test can fail */ 170 response[0] = MMC_RESP3(drive);
148 panicf("Response timeout"); 171 response[1] = MMC_RESP2(drive);
149 } 172 response[2] = MMC_RESP1(drive);
150 else if(status & (MCI_CMD_CRC_FAIL|MCI_CMD_RESP_END)) 173 response[3] = MMC_RESP0(drive);
151 { /* resp received */
152 cmd->resp[0] = MMC_RESP0(drive);
153 if(cmd->flags & MMC_LONG_RESP)
154 {
155 cmd->resp[1] = MMC_RESP1(drive);
156 cmd->resp[2] = MMC_RESP2(drive);
157 cmd->resp[3] = MMC_RESP3(drive);
158 }
159 break;
160 } 174 }
175 else
176 response[0] = MMC_RESP0(drive);
177 return true;
161 } 178 }
162 else 179 }
163 if(status & MCI_CMD_SENT) 180 else if(status & MCI_CMD_SENT)
164 break; 181 return true;
165
166 } while(1);
167 182
168 MMC_CLEAR(drive) = 0x7ff; 183 return false;
169 return status;
170} 184}
171 185
172static void sd_init_card(const int drive) 186static int sd_init_card(const int drive)
173{ 187{
174 struct mmc_command cmd_app, cmd_op_cond, cmd_idle, cmd_if_cond; 188 unsigned int c_size;
175 int status; 189 unsigned long c_mult;
176 bool sdhc;
177 190
178#ifdef DEBUG 191 int response;
179 reset_screen(); 192 int max_tries = 100; /* max acmd41 attemps */
180 printf("now - powered up"); 193 bool sdhc;
181#endif
182 194
183 cmd_idle.cmd = GO_IDLE_STATE; 195 if(!send_cmd(drive, GO_IDLE_STATE, 0, MMC_NO_FLAGS, NULL))
184 cmd_idle.arg = 0; 196 return -1;
185 cmd_idle.flags = MMC_NO_FLAGS;
186 if(send_cmd(drive, &cmd_idle) != MCI_CMD_SENT)
187 panicf("goto idle failed!");
188#ifdef DEBUG
189 else
190 printf("now - idle");
191#endif
192 197
193 mci_delay(); 198 mci_delay();
194 199
195 cmd_if_cond.cmd = SEND_IF_COND;
196 cmd_if_cond.arg = (1 /* 2.7-3.6V */ << 8) | 0xAA /* check pattern */;
197 cmd_if_cond.flags = MMC_RESP | MMC_ARG;
198
199 cmd_app.cmd = APP_CMD;
200 cmd_app.flags = MMC_RESP | MMC_ARG;
201 cmd_app.arg = 0; /* 31:16 RCA (0) , 15:0 stuff bits */
202
203 cmd_op_cond.cmd = SEND_OP_COND;
204 cmd_op_cond.flags = MMC_RESP | MMC_ARG;
205
206#ifdef DEBUG
207 printf("now - card powering up");
208#endif
209
210 sdhc = false; 200 sdhc = false;
211 status = send_cmd(drive, &cmd_if_cond); 201 if(send_cmd(drive, SEND_IF_COND, 0x1AA, MMC_RESP|MMC_ARG, &response))
212 if(status & (MCI_CMD_CRC_FAIL|MCI_CMD_RESP_END)) 202 if((response & 0xFFF) == 0x1AA)
213 {
214 if((cmd_if_cond.resp[0] & 0xFFF) == cmd_if_cond.arg)
215 sdhc = true; 203 sdhc = true;
216#ifdef DEBUG
217 else
218 printf("Bad resp: %x",cmd_if_cond.arg);
219#endif
220 }
221#ifdef DEBUG
222 else
223 printf("cmd_if_cond stat: 0x%x",status);
224
225 printf("%s Capacity",sdhc?"High":"Normal");
226 mci_delay();
227 mci_delay();
228 mci_delay();
229#endif
230 204
231#ifdef DEBUG
232 int loop = 0;
233#endif
234 do { 205 do {
235 mci_delay(); 206 mci_delay();
236 mci_delay(); 207
237#ifdef DEBUG
238 reset_screen();
239 printf("Loop number #%d", ++loop);
240#endif
241 /* app_cmd */ 208 /* app_cmd */
242 status = send_cmd(drive, &cmd_app); 209 if( !send_cmd(drive, APP_CMD, 0, MMC_RESP|MMC_ARG, &response) ||
243 if( !(status & (MCI_CMD_CRC_FAIL|MCI_CMD_RESP_END)) || 210 !(response & (1<<5)) )
244 !(cmd_app.resp[0] & (1<<5)) )
245 { 211 {
246 panicf("app_cmd failed"); 212 return -2;
247 } 213 }
248 214
249 cmd_op_cond.arg = sdhc ? 0x40FF8000 : (8<<0x14); /* ocr */ 215 /* acmd41 */
250 status = send_cmd(drive, &cmd_op_cond); 216 if(!send_cmd(drive, SD_APP_OP_COND, (sdhc ? 0x40FF8000 : (1<<23)),
251 if(!(status & (MCI_CMD_CRC_FAIL|MCI_CMD_RESP_END))) 217 MMC_RESP|MMC_ARG, &card_info[drive].ocr))
252 panicf("cmd_op_cond failed"); 218 return -3;
253 219
254#ifdef DEBUG 220 } while(!(card_info[drive].ocr & (1<<31)) && max_tries--);
255 printf("OP COND: 0x%.8x", cmd_op_cond.resp[0]); 221
256#endif 222 if(!max_tries)
257 } while(!(cmd_op_cond.resp[0] & (1<<31))); /* until card is powered up */ 223 return -4;
224
225 /* send CID */
226 if(!send_cmd(drive, ALL_SEND_CID, 0, MMC_RESP|MMC_LONG_RESP|MMC_ARG,
227 card_info[drive].cid))
228 return -5;
229
230 /* send RCA */
231 if(!send_cmd(drive, SEND_RELATIVE_ADDR, 0, MMC_RESP|MMC_ARG,
232 &card_info[drive].rca))
233 return -6;
258 234
259#ifdef DEBUG 235 /* send CSD */
260 printf("now - card ready !"); 236 if(!send_cmd(drive, SEND_CSD, card_info[drive].rca,
237 MMC_RESP|MMC_LONG_RESP|MMC_ARG, card_info[drive].csd))
238 return -7;
239
240 /* These calculations come from the Sandisk SD card product manual */
241 if( (card_info[drive].csd[3]>>30) == 0)
242 {
243 /* CSD version 1.0 */
244 c_size = ((card_info[drive].csd[2] & 0x3ff) << 2) + (card_info[drive].csd[1]>>30) + 1;
245 c_mult = 4 << ((card_info[drive].csd[1] >> 15) & 7);
246 card_info[drive].max_read_bl_len = 1 << ((card_info[drive].csd[2] >> 16) & 15);
247 card_info[drive].block_size = BLOCK_SIZE; /* Always use 512 byte blocks */
248 card_info[drive].numblocks = c_size * c_mult * (card_info[drive].max_read_bl_len/512);
249 card_info[drive].capacity = card_info[drive].numblocks * card_info[drive].block_size;
250 }
251#ifdef HAVE_MULTIVOLUME
252 else if( (card_info[drive].csd[3]>>30) == 1)
253 {
254 /* CSD version 2.0 */
255 c_size = ((card_info[drive].csd[2] & 0x3f) << 16) + (card_info[drive].csd[1]>>16) + 1;
256 card_info[drive].max_read_bl_len = 1 << ((card_info[drive].csd[2] >> 16) & 0xf);
257 card_info[drive].block_size = BLOCK_SIZE; /* Always use 512 byte blocks */
258 card_info[drive].numblocks = c_size << 10;
259 card_info[drive].capacity = card_info[drive].numblocks * card_info[drive].block_size;
260 }
261#endif 261#endif
262
263 if(!send_cmd(drive, SELECT_CARD, card_info[drive].rca, MMC_ARG, NULL))
264 return -9;
265
266 if(!send_cmd(drive, APP_CMD, card_info[drive].rca, MMC_ARG, NULL))
267 return -10;
268
269 if(!send_cmd(drive, SET_BUS_WIDTH, card_info[drive].rca | 2, MMC_ARG, NULL))
270 return -11;
271
272 if(!send_cmd(drive, SET_BLOCKLEN, card_info[drive].block_size, MMC_ARG,
273 NULL))
274 return -12;
275
276 card_info[drive].initialized = 1;
277
278 mci_set_clock_divider(drive, 1); /* full speed */
279
280 return 0;
262} 281}
263 282
283static void sd_thread(void) __attribute__((noreturn));
284static void sd_thread(void)
285{
286 struct queue_event ev;
287 bool idle_notified = false;
288
289 while (1)
290 {
291 queue_wait_w_tmo(&sd_queue, &ev, HZ);
292
293 switch ( ev.id )
294 {
295#ifdef HAVE_HOTSWAP
296 case SYS_HOTSWAP_INSERTED:
297 case SYS_HOTSWAP_EXTRACTED:
298 fat_lock(); /* lock-out FAT activity first -
299 prevent deadlocking via disk_mount that
300 would cause a reverse-order attempt with
301 another thread */
302 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
303 into driver that bypass the fat cache */
304
305 /* We now have exclusive control of fat cache and ata */
306
307 disk_unmount(1); /* release "by force", ensure file
308 descriptors aren't leaked and any busy
309 ones are invalid if mounting */
310
311 /* Force card init for new card, re-init for re-inserted one or
312 * clear if the last attempt to init failed with an error. */
313 card_info[1].initialized = 0;
314
315 if (ev.id == SYS_HOTSWAP_INSERTED)
316 disk_mount(1);
317
318 queue_broadcast(SYS_FS_CHANGED, 0);
319
320 /* Access is now safe */
321 mutex_unlock(&sd_mtx);
322 fat_unlock();
323 break;
324#endif
325 case SYS_TIMEOUT:
326 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
327 {
328 idle_notified = false;
329 }
330 else
331 {
332 /* never let a timer wrap confuse us */
333 next_yield = current_tick;
334
335 if (!idle_notified)
336 {
337 call_storage_idle_notifys(false);
338 idle_notified = true;
339 }
340 }
341 break;
342#if 0
343 case SYS_USB_CONNECTED:
344 usb_acknowledge(SYS_USB_CONNECTED_ACK);
345 /* Wait until the USB cable is extracted again */
346 usb_wait_for_disconnect(&sd_queue);
347
348 break;
349 case SYS_USB_DISCONNECTED:
350 usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
351 break;
352#endif
353 }
354 }
355}
264static void init_pl180_controller(const int drive) 356static void init_pl180_controller(const int drive)
265{ 357{
266 MMC_COMMAND(drive) = MMC_DATACTRL(drive) = 0; 358#ifdef BOOTLOADER
359 MMC_COMMAND(drive) = MMC_DATA_CTRL(drive) = 0;
267 MMC_CLEAR(drive) = 0x7ff; 360 MMC_CLEAR(drive) = 0x7ff;
268 361
269 MMC_MASK0(drive) = MMC_MASK1(drive) = 0; /* disable all interrupts */ 362 MMC_MASK0(drive) = MMC_MASK1(drive) = 0; /* disable all interrupts */
@@ -281,10 +374,16 @@ static void init_pl180_controller(const int drive)
281 374
282 /* set MCLK divider */ 375 /* set MCLK divider */
283 mci_set_clock_divider(drive, 200); 376 mci_set_clock_divider(drive, 200);
377#else
378 /* controller already initialized by bootloader */
379 (void)drive;
380#endif /* BOOTLOADER */
284} 381}
285 382
286int sd_init(void) 383int sd_init(void)
287{ 384{
385 int ret;
386
288 CGU_IDE = (1<<7) /* AHB interface enable */ | 387 CGU_IDE = (1<<7) /* AHB interface enable */ |
289 (1<<6) /* interface enable */ | 388 (1<<6) /* interface enable */ |
290 (2<<2) /* clock didiver = 2+1 */ | 389 (2<<2) /* clock didiver = 2+1 */ |
@@ -299,23 +398,55 @@ int sd_init(void)
299 CCU_IO |= 4; 398 CCU_IO |= 4;
300 399
301 init_pl180_controller(NAND_AS3525); 400 init_pl180_controller(NAND_AS3525);
302 sd_init_card(NAND_AS3525); 401 ret = sd_init_card(NAND_AS3525);
402 if(ret < 0)
403 return ret;
303 404
304#ifdef HAVE_MULTIVOLUME 405#ifdef HAVE_MULTIVOLUME
305 init_pl180_controller(SD_AS3525); 406 init_pl180_controller(SD_AS3525);
306 sd_init_card(SD_AS3525); 407 ret = sd_init_card(SD_AS3525);
408 if(ret < 0)
409 return ret;
307#endif 410#endif
308 411
412 queue_init(&sd_queue, true);
413 create_thread(sd_thread, sd_stack, sizeof(sd_stack), 0,
414 sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU));
415
309 return 0; 416 return 0;
310} 417}
311 418
312int sd_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) 419#ifdef STORAGE_GET_INFO
420void sd_get_info(IF_MV2(int drive,) struct storage_info *info)
313{ 421{
314 (void)start; 422#ifndef HAVE_MULTIVOLUME
315 (void)count; 423 const int drive=0;
316 (void)buf; 424#endif
317 return 0; /* TODO */ 425 info->sector_size=card_info[drive].block_size;
426 info->num_sectors=card_info[drive].numblocks;
427 info->vendor="Rockbox";
428 info->product = (drive == 0) ? "Internal Storage" : "SD Card Slot";
429 info->revision="0.00";
430}
431#endif
432
433#ifdef HAVE_HOTSWAP
434bool sd_removable(IF_MV_NONVOID(int drive))
435{
436#ifndef HAVE_MULTIVOLUME
437 const int drive=0;
438#endif
439 return (drive==1);
440}
441
442bool sd_present(IF_MV_NONVOID(int drive))
443{
444#ifndef HAVE_MULTIVOLUME
445 const int drive=0;
446#endif
447 return (card_info[drive].initialized && card_info[drive].numblocks > 0);
318} 448}
449#endif
319 450
320int sd_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf) 451int sd_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf)
321{ 452{
@@ -324,3 +455,178 @@ int sd_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const vo
324 (void)buf; 455 (void)buf;
325 return 0; /* TODO */ 456 return 0; /* TODO */
326} 457}
458
459static bool sd_poll_status(const int drive, unsigned int trigger, long timeout)
460{
461 long t = current_tick;
462
463 while ((MMC_STATUS(drive) & trigger) == 0)
464 {
465 long time = current_tick;
466
467 if (TIME_AFTER(time, next_yield))
468 {
469 long ty = current_tick;
470 yield();
471 timeout += current_tick - ty;
472 next_yield = ty + MIN_YIELD_PERIOD;
473 }
474
475 if (TIME_AFTER(time, t + timeout))
476 return false;
477 }
478
479 return true;
480}
481
482static int sd_wait_for_state(const int drive, unsigned int state)
483{
484 unsigned int response = 0;
485 unsigned int timeout = 0x80000;
486
487 long t = current_tick;
488
489 while (1)
490 {
491 long us;
492
493 if(!send_cmd(drive, SEND_STATUS, card_info[drive].rca,
494 MMC_RESP|MMC_ARG, &response))
495 return -1;
496
497 if (((response >> 9) & 0xf) == state)
498 return 0;
499
500 if(TIME_AFTER(current_tick, t + timeout))
501 return -1;
502
503 us = current_tick;
504 if (TIME_AFTER(us, next_yield))
505 {
506 yield();
507 timeout += current_tick - us;
508 next_yield = us + MIN_YIELD_PERIOD;
509 }
510 }
511}
512
513int sd_read_sectors(IF_MV2(int drive,) unsigned long start, int incount,
514 void* inbuf)
515{
516#ifndef HAVE_MULTIVOLUME
517 const int drive = 0;
518#endif
519 int ret;
520 unsigned char *buf_end, *buf = inbuf;
521 int remaining = incount;
522 const unsigned long *fifo_base = MMC_FIFO(drive);
523
524 start += 20480; /* skip SanDisk OF */
525
526 /* TODO: Add DMA support. */
527
528 mutex_lock(&sd_mtx);
529
530#ifdef HAVE_MULTIVOLUME
531 if (drive != 0 && !card_detect_target())
532 {
533 /* no external sd-card inserted */
534 ret = -88;
535 goto sd_read_error;
536 }
537#endif
538
539 if (card_info[drive].initialized < 0)
540 {
541 ret = card_info[drive].initialized;
542 goto sd_read_error;
543 }
544
545 last_disk_activity = current_tick;
546
547 ret = sd_wait_for_state(drive, TRAN);
548 if (ret < 0)
549 goto sd_read_error;
550
551 while(remaining)
552 {
553 /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH
554 * register, so we have to transfer maximum 127 sectors at a time. */
555 int transfer = (remaining >= 128) ? 127 : remaining; /* sectors */
556
557 if(card_info[drive].ocr & (1<<30) ) /* SDHC */
558 ret = send_cmd(drive, READ_MULTIPLE_BLOCK, start, MMC_ARG, NULL);
559 else
560 ret = send_cmd(drive, READ_MULTIPLE_BLOCK, start * BLOCK_SIZE,
561 MMC_ARG, NULL);
562
563 if (ret < 0)
564 goto sd_read_error;
565
566 /* TODO: Don't assume BLOCK_SIZE == SECTOR_SIZE */
567
568
569 MMC_DATA_TIMER(drive) = 0x1000000; /* FIXME: arbitrary */
570 MMC_DATA_LENGTH(drive) = transfer * card_info[drive].block_size;
571 MMC_DATA_CTRL(drive) = (1<<0) /* enable */ |
572 (1<<1) /* from card to controller */ |
573 (9<<4) /* 2^9 = 512 */ ;
574
575 buf_end = buf + transfer * card_info[drive].block_size;
576
577 while(buf < buf_end)
578 {
579 /* Wait for the FIFO to be half full */
580 if (!sd_poll_status(drive, ((1<<15)), 100))
581 {
582 ret = -42;
583 goto sd_read_error;
584 }
585
586 asm volatile(
587 "ldmia %2, {r0-r7} \n" /* load 8 * 4 bytes */
588 "stmia %1!, {r0-r7} \n" /* store 8 * 4 bytes */
589 :"=r"(buf) /* output */
590 :"r"(buf), "r"(fifo_base) /* input */
591 :"r0","r1","r2","r3","r4","r5","r6","r7","r8" /* clobbers */
592 );
593 }
594
595 remaining -= transfer;
596 start += transfer;
597 last_disk_activity = current_tick;
598
599 if(!send_cmd(drive, STOP_TRANSMISSION, 0, MMC_NO_FLAGS, NULL))
600 {
601 ret = -666;
602 goto sd_read_error;
603 }
604
605 ret = sd_wait_for_state(drive, TRAN);
606 if (ret < 0)
607 goto sd_read_error;
608
609 }
610 while (1)
611 {
612 mutex_unlock(&sd_mtx);
613
614 return ret;
615
616sd_read_error:
617 card_info[drive].initialized = 0;
618 }
619}
620
621void sd_sleep(void)
622{
623}
624
625void sd_spin(void)
626{
627}
628
629void sd_spindown(int seconds)
630{
631 (void)seconds;
632}
diff --git a/firmware/target/arm/as3525/kernel-as3525.c b/firmware/target/arm/as3525/kernel-as3525.c
index 73031b9eb5..c534d5e130 100644
--- a/firmware/target/arm/as3525/kernel-as3525.c
+++ b/firmware/target/arm/as3525/kernel-as3525.c
@@ -32,12 +32,9 @@ void INT_TIMER2(void)
32 32
33void tick_start(unsigned int interval_in_ms) 33void tick_start(unsigned int interval_in_ms)
34{ 34{
35#ifdef BOOTLOADER
36 (void) interval_in_ms;
37#else
38 int phi = 0; /* prescaler bits */ 35 int phi = 0; /* prescaler bits */
39 int prescale = 1; 36 int prescale = 1;
40 int cycles = 64000 * interval_in_ms; /* pclk is clocked at 64MHz */ 37 int cycles = 1000 * interval_in_ms; /* pclk is clocked at 64MHz */
41 38
42 while(cycles > 0x10000) 39 while(cycles > 0x10000)
43 { 40 {
@@ -57,5 +54,4 @@ void tick_start(unsigned int interval_in_ms)
57 /* /!\ bit 4 (reserved) must not be modified 54 /* /!\ bit 4 (reserved) must not be modified
58 * periodic mode, interrupt enabled, 16 bits counter */ 55 * periodic mode, interrupt enabled, 16 bits counter */
59 TIMER2_CONTROL = (TIMER2_CONTROL & (1<<4)) | 0xe0 | (phi<<2); 56 TIMER2_CONTROL = (TIMER2_CONTROL & (1<<4)) | 0xe0 | (phi<<2);
60#endif
61} 57}
diff --git a/firmware/target/arm/as3525/sansa-clip/system-target.h b/firmware/target/arm/as3525/sansa-clip/system-target.h
index b712d1c124..dc9d77f3dc 100644
--- a/firmware/target/arm/as3525/sansa-clip/system-target.h
+++ b/firmware/target/arm/as3525/sansa-clip/system-target.h
@@ -23,6 +23,8 @@
23 23
24#include "system-arm.h" 24#include "system-arm.h"
25 25
26#define CPUFREQ_MAX 250000000 26#define CPUFREQ_MAX 250000000
27#define CPUFREQ_DEFAULT 250000000
28#define CPUFREQ_NORMAL 250000000
27 29
28#endif /* SYSTEM_TARGET_H */ 30#endif /* SYSTEM_TARGET_H */
diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c
index 544371e5a4..240cb63b7c 100644
--- a/firmware/target/arm/as3525/system-as3525.c
+++ b/firmware/target/arm/as3525/system-as3525.c
@@ -23,6 +23,7 @@
23#include "kernel.h" 23#include "kernel.h"
24#include "system.h" 24#include "system.h"
25#include "panic.h" 25#include "panic.h"
26#include "as3525-codec.h"
26 27
27#define default_interrupt(name) \ 28#define default_interrupt(name) \
28 extern __attribute__((weak,alias("UIRQ"))) void name (void) 29 extern __attribute__((weak,alias("UIRQ"))) void name (void)
@@ -123,6 +124,7 @@ void fiq_handler(void)
123 ); 124 );
124} 125}
125 126
127#ifdef BOOTLOADER
126static void sdram_delay(void) 128static void sdram_delay(void)
127{ 129{
128 int delay = 1024; /* arbitrary */ 130 int delay = 1024; /* arbitrary */
@@ -192,9 +194,11 @@ static void sdram_init(void)
192 194
193 MPMC_DYNAMIC_CONFIG_0 |= (1<<19); /* buffer enable */ 195 MPMC_DYNAMIC_CONFIG_0 |= (1<<19); /* buffer enable */
194} 196}
197#endif
195 198
196void system_init(void) 199void system_init(void)
197{ 200{
201#ifdef BOOTLOADER
198#if 0 /* the GPIO clock is already enabled by the dualboot function */ 202#if 0 /* the GPIO clock is already enabled by the dualboot function */
199 CGU_PERI |= CGU_GPIO_CLOCK_ENABLE; 203 CGU_PERI |= CGU_GPIO_CLOCK_ENABLE;
200#endif 204#endif
@@ -235,6 +239,7 @@ void system_init(void)
235 /* enable VIC */ 239 /* enable VIC */
236 CGU_PERI |= CGU_VIC_CLOCK_ENABLE; 240 CGU_PERI |= CGU_VIC_CLOCK_ENABLE;
237 VIC_INT_SELECT = 0; /* only IRQ, no FIQ */ 241 VIC_INT_SELECT = 0; /* only IRQ, no FIQ */
242#endif
238} 243}
239 244
240void system_reboot(void) 245void system_reboot(void)
@@ -246,3 +251,15 @@ int system_memory_guard(int newmode)
246 (void)newmode; 251 (void)newmode;
247 return 0; 252 return 0;
248} 253}
254
255void power_off(void)
256{
257 int system;
258 system = as3525_codec_read(0x20);
259 system &= ~1; /* clear bit 0 of system register */
260 as3525_codec_write(0x20, system);
261
262 /* TODO : turn off peripherals properly ? */
263
264 while(1);
265}