diff options
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/as3525/app.lds | 126 | ||||
-rw-r--r-- | firmware/target/arm/as3525/ata_sd_as3525.c | 590 | ||||
-rw-r--r-- | firmware/target/arm/as3525/kernel-as3525.c | 6 | ||||
-rw-r--r-- | firmware/target/arm/as3525/sansa-clip/system-target.h | 4 | ||||
-rw-r--r-- | firmware/target/arm/as3525/system-as3525.c | 17 |
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 | |||
3 | ENTRY(start) | ||
4 | |||
5 | OUTPUT_FORMAT(elf32-littlearm) | ||
6 | OUTPUT_ARCH(arm) | ||
7 | STARTUP(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 | |||
31 | MEMORY | ||
32 | { | ||
33 | IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE | ||
34 | DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE | ||
35 | } | ||
36 | |||
37 | SECTIONS | ||
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" |
34 | static 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 */ | 75 | static 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 | 85 | static tSDCardInfo card_info[NUM_VOLUMES]; |
68 | #define DEBUG | ||
69 | void reset_screen(void); | ||
70 | void printf(const char *format, ...); | ||
71 | #endif | ||
72 | 86 | ||
73 | struct mmc_command | 87 | /* for compatibility */ |
74 | { | 88 | static long last_disk_activity = -1; |
75 | int cmd; | 89 | |
76 | int arg; | 90 | #define MIN_YIELD_PERIOD 1000 |
77 | int resp[4]; | 91 | static long next_yield = 0; |
78 | int flags; | 92 | |
79 | }; | 93 | /* Shoot for around 75% usage */ |
94 | static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)]; | ||
95 | static const char sd_thread_name[] = "ata/sd"; | ||
96 | static struct mutex sd_mtx SHAREDBSS_ATTR; | ||
97 | static struct event_queue sd_queue; | ||
80 | 98 | ||
81 | static inline void mci_delay(void) { int i = 0xffff; while(i--) ; } | 99 | static 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 | ||
109 | static int send_cmd(const int drive, struct mmc_command *cmd) | 127 | static 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 | ||
172 | static void sd_init_card(const int drive) | 186 | static 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 | ||
283 | static void sd_thread(void) __attribute__((noreturn)); | ||
284 | static 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 | } | ||
264 | static void init_pl180_controller(const int drive) | 356 | static 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 | ||
286 | int sd_init(void) | 383 | int 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 | ||
312 | int sd_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) | 419 | #ifdef STORAGE_GET_INFO |
420 | void 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 | ||
434 | bool 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 | |||
442 | bool 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 | ||
320 | int sd_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf) | 451 | int 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 | |||
459 | static 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 | |||
482 | static 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 | |||
513 | int 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 | |||
616 | sd_read_error: | ||
617 | card_info[drive].initialized = 0; | ||
618 | } | ||
619 | } | ||
620 | |||
621 | void sd_sleep(void) | ||
622 | { | ||
623 | } | ||
624 | |||
625 | void sd_spin(void) | ||
626 | { | ||
627 | } | ||
628 | |||
629 | void 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 | ||
33 | void tick_start(unsigned int interval_in_ms) | 33 | void 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 | ||
126 | static void sdram_delay(void) | 128 | static 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 | ||
196 | void system_init(void) | 199 | void 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 | ||
240 | void system_reboot(void) | 245 | void 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 | |||
255 | void 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 | } | ||