summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootloader/sansa_as3525.c5
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/target/arm/as3525/ata_sd_as3525.c341
-rw-r--r--firmware/target/arm/as3525/mmci.h123
4 files changed, 469 insertions, 1 deletions
diff --git a/bootloader/sansa_as3525.c b/bootloader/sansa_as3525.c
index a88e206c3b..df6f789135 100644
--- a/bootloader/sansa_as3525.c
+++ b/bootloader/sansa_as3525.c
@@ -30,6 +30,7 @@
30#include "backlight-target.h" 30#include "backlight-target.h"
31#include "as3525-codec.h" 31#include "as3525-codec.h"
32#include "common.h" 32#include "common.h"
33#include "ata.h"
33 34
34int show_logo(void); 35int show_logo(void);
35void main(void) 36void main(void)
@@ -52,7 +53,9 @@ void main(void)
52 buf[i] = as3525_codec_read(0x38 + i); 53 buf[i] = as3525_codec_read(0x38 + i);
53 } 54 }
54 printf("ID: %02X%02X%02X%02X%02X%02X%02X%02X", buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); 55 printf("ID: %02X%02X%02X%02X%02X%02X%02X%02X", buf[7], buf[6], buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]);
55 56
57 ata_init();
58
56#ifdef SANSA_CLIP 59#ifdef SANSA_CLIP
57 /* Use hardware scrolling */ 60 /* Use hardware scrolling */
58 61
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 53b33406b5..400074a0e9 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -330,6 +330,7 @@ target/arm/pnx0101/system-pnx0101.c
330 330
331#if CONFIG_CPU == AS3525 331#if CONFIG_CPU == AS3525
332target/arm/as3525/system-as3525.c 332target/arm/as3525/system-as3525.c
333target/arm/as3525/ata_sd_as3525.c
333#endif 334#endif
334 335
335#if defined(CPU_PP) 336#if defined(CPU_PP)
diff --git a/firmware/target/arm/as3525/ata_sd_as3525.c b/firmware/target/arm/as3525/ata_sd_as3525.c
new file mode 100644
index 0000000000..e8f899bc37
--- /dev/null
+++ b/firmware/target/arm/as3525/ata_sd_as3525.c
@@ -0,0 +1,341 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright © 2008 Rafaël Carré
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/* Driver for the ARM PL180 SD/MMC controller inside AS3525 SoC */
23
24#include "config.h" /* for HAVE_MULTIVOLUME */
25
26#include "as3525.h"
27#include "mmci.h"
28#include "panic.h"
29#include "stdbool.h"
30#include "ata.h"
31
32#define NAND_AS3525 0
33#define SD_AS3525 1
34static int pl180_base[2] = { NAND_FLASH_BASE, SD_MCI_BASE };
35
36/* ARM PL180 registers */
37#define MMC_POWER(i) (*(volatile unsigned long *) (pl180_base[i]+0x00))
38#define MMC_CLOCK(i) (*(volatile unsigned long *) (pl180_base[i]+0x04))
39#define MMC_ARGUMENT(i) (*(volatile unsigned long *) (pl180_base[i]+0x08))
40#define MMC_COMMAND(i) (*(volatile unsigned long *) (pl180_base[i]+0x0C))
41#define MMC_RESPCMD(i) (*(volatile unsigned long *) (pl180_base[i]+0x10))
42#define MMC_RESP0(i) (*(volatile unsigned long *) (pl180_base[i]+0x14))
43#define MMC_RESP1(i) (*(volatile unsigned long *) (pl180_base[i]+0x18))
44#define MMC_RESP2(i) (*(volatile unsigned long *) (pl180_base[i]+0x1C))
45#define MMC_RESP3(i) (*(volatile unsigned long *) (pl180_base[i]+0x20))
46#define MMC_DATACTRL(i) (*(volatile unsigned long *) (pl180_base[i]+0x2C))
47#define MMC_STATUS(i) (*(volatile unsigned long *) (pl180_base[i]+0x34))
48#define MMC_CLEAR(i) (*(volatile unsigned long *) (pl180_base[i]+0x38))
49#define MMC_MASK0(i) (*(volatile unsigned long *) (pl180_base[i]+0x3C))
50#define MMC_MASK1(i) (*(volatile unsigned long *) (pl180_base[i]+0x40))
51#define MMC_SELECT(i) (*(volatile unsigned long *) (pl180_base[i]+0x44))
52
53
54/* SD commands */
55#define GO_IDLE_STATE 0
56#define MMC_CMD_READ_CID 2
57#define SEND_IF_COND 8
58#define SEND_OP_COND 41
59#define APP_CMD 55
60
61/* command flags */
62#define MMC_NO_FLAGS (0<<0)
63#define MMC_RESP (1<<0)
64#define MMC_LONG_RESP (1<<1)
65#define MMC_ARG (1<<2)
66
67#ifdef BOOTLOADER
68#define DEBUG
69void reset_screen(void);
70void printf(const char *format, ...);
71#endif
72
73struct mmc_command
74{
75 int cmd;
76 int arg;
77 int resp[4];
78 int flags;
79};
80
81static inline void mci_delay(void) { int i = 0xffff; while(i--) ; }
82
83static void mci_set_clock_divider(const int drive, int divider)
84{
85 int clock = MMC_CLOCK(drive);
86
87 if(divider > 1)
88 {
89 /* use divide logic */
90 clock &= ~MCI_CLK_BYPASS;
91
92 /* convert divider to MMC_CLOCK logic */
93 divider = (divider/2) - 1;
94 if(divider >= 256)
95 divider = 255;
96 }
97 else
98 {
99 /* bypass dividing logic */
100 clock |= MCI_CLK_BYPASS;
101 divider = 0;
102 }
103
104 MMC_CLOCK(drive) = clock | divider;
105
106 mci_delay();
107}
108
109static int send_cmd(const int drive, struct mmc_command *cmd)
110{
111 int val, status;
112
113 while(MMC_STATUS(drive) & MCI_CMDACTIVE); /* useless */
114
115 if(MMC_COMMAND(drive) & MCI_CPSM_ENABLE) /* clears existing command */
116 {
117 MMC_COMMAND(drive) = 0;
118 mci_delay();
119 }
120
121 val = cmd->cmd | MCI_CPSM_ENABLE;
122 if(cmd->flags & MMC_RESP)
123 {
124 val |= MCI_CPSM_RESPONSE;
125 if(cmd->flags & MMC_LONG_RESP)
126 val |= MCI_CPSM_LONGRSP;
127 }
128
129 MMC_CLEAR(drive) = 0x7ff;
130
131 MMC_ARGUMENT(drive) = (cmd->flags & MMC_ARG) ? cmd->arg : 0;
132 MMC_COMMAND(drive) = val;
133
134 while(MMC_STATUS(drive) & MCI_CMDACTIVE);
135
136 MMC_COMMAND(drive) = 0;
137 MMC_ARGUMENT(drive) = ~0;
138
139 do
140 {
141 status = MMC_STATUS(drive);
142 if(cmd->flags & MMC_RESP)
143 {
144 if(status & MCI_CMDTIMEOUT)
145 {
146 if(cmd->cmd == SEND_IF_COND)
147 break; /* SDHC test can fail */
148 panicf("Response timeout");
149 }
150 else if(status & (MCI_CMDCRCFAIL|MCI_CMDRESPEND))
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 }
161 }
162 else
163 if(status & MCI_CMDSENT)
164 break;
165
166 } while(1);
167
168 MMC_CLEAR(drive) = 0x7ff;
169 return status;
170}
171
172static void sd_init_card(const int drive)
173{
174 struct mmc_command cmd_app, cmd_op_cond, cmd_idle, cmd_if_cond;
175 int status;
176 bool sdhc;
177
178#ifdef DEBUG
179 reset_screen();
180 printf("now - powered up");
181#endif
182
183 cmd_idle.cmd = GO_IDLE_STATE;
184 cmd_idle.arg = 0;
185 cmd_idle.flags = MMC_NO_FLAGS;
186 if(send_cmd(drive, &cmd_idle) != MCI_CMDSENT)
187 panicf("goto idle failed!");
188#ifdef DEBUG
189 else
190 printf("now - idle");
191#endif
192
193 mci_delay();
194
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;
211 status = send_cmd(drive, &cmd_if_cond);
212 if(status & (MCI_CMDCRCFAIL|MCI_CMDRESPEND))
213 {
214 if((cmd_if_cond.resp[0] & 0xFFF) == cmd_if_cond.arg)
215 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
231#ifdef DEBUG
232 int loop = 0;
233#endif
234 do {
235 mci_delay();
236 mci_delay();
237#ifdef DEBUG
238 reset_screen();
239 printf("Loop number #%d", ++loop);
240#endif
241 /* app_cmd */
242 status = send_cmd(drive, &cmd_app);
243 if( !(status & (MCI_CMDCRCFAIL|MCI_CMDRESPEND)) ||
244 !(cmd_app.resp[0] & (1<<5)) )
245 {
246 panicf("app_cmd failed");
247 }
248
249 cmd_op_cond.arg = sdhc ? 0x40FF8000 : (8<<0x14); /* ocr */
250 status = send_cmd(drive, &cmd_op_cond);
251 if(!(status & (MCI_CMDCRCFAIL|MCI_CMDRESPEND)))
252 panicf("cmd_op_cond failed");
253
254#ifdef DEBUG
255 printf("OP COND: 0x%.8x", cmd_op_cond.resp[0]);
256#endif
257 } while(!(cmd_op_cond.resp[0] & (1<<31))); /* until card is powered up */
258
259#ifdef DEBUG
260 printf("now - card ready !");
261#endif
262}
263
264static void init_pl180_controller(const int drive)
265{
266 MMC_COMMAND(drive) = MMC_DATACTRL(drive) = 0;
267 MMC_CLEAR(drive) = 0x7ff;
268
269 MMC_MASK0(drive) = MMC_MASK1(drive) = 0; /* disable all interrupts */
270
271 MMC_POWER(drive) = MCI_PWR_UP | (10 /*voltage*/ << 2); /* use OF voltage */
272 mci_delay();
273
274 MMC_POWER(drive) |= MCI_PWR_ON;
275 mci_delay();
276
277 MMC_SELECT(drive) = 0;
278
279 MMC_CLOCK(drive) = MCI_CLK_ENABLE;
280 MMC_CLOCK(drive) &= ~MCI_CLK_PWRSAVE;
281
282 /* set MCLK divider */
283 mci_set_clock_divider(drive, 200);
284}
285
286int ata_init(void)
287{
288 /* reset peripherals */
289
290 CCU_SRC =
291#ifdef HAVE_MULTIVOLUME
292 CCU_SRC_SDMCI_EN |
293#endif
294 CCU_SRC_NAF_EN | CCU_SRC_IDE_EN | CCU_SRC_IDE_AHB_EN | CCU_SRC_MST_EN;
295
296 CCU_SRL = CCU_SRL_MAGIC_NUMBER;
297 CCU_SRL = 0;
298
299 GPIOC_DIR &= ~(1<<1);
300 if(GPIOC_PIN(1))
301 CCU_SPARE1 |= 4; /* sets bit 3 of undocumented register */
302 else
303 CCU_SPARE1 &= ~4; /* or clear it */
304
305 CGU_IDE = (1<<7)|(1<<6); /* enable, 24MHz clock */
306 CGU_MEMSTICK = (1<<8); /* enable, 24MHz clock */
307
308 CGU_PERI |= CGU_NAF_CLOCK_ENABLE;
309#ifdef HAVE_MULTIVOLUME
310 CGU_PERI |= CGU_MCI_CLOCK_ENABLE;
311#endif
312
313 CCU_IO &= ~8; /* bits 3:2 = 01, xpd is SD interface */
314 CCU_IO |= 4;
315
316 init_pl180_controller(NAND_AS3525);
317 sd_init_card(NAND_AS3525);
318
319#ifdef HAVE_MULTIVOLUME
320 init_pl180_controller(SD_AS3525);
321 sd_init_card(SD_AS3525);
322#endif
323
324 return 0;
325}
326
327int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf)
328{
329 (void)start;
330 (void)count;
331 (void)buf;
332 return 0; /* TODO */
333}
334
335int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf)
336{
337 (void)start;
338 (void)count;
339 (void)buf;
340 return 0; /* TODO */
341}
diff --git a/firmware/target/arm/as3525/mmci.h b/firmware/target/arm/as3525/mmci.h
new file mode 100644
index 0000000000..284eee0c75
--- /dev/null
+++ b/firmware/target/arm/as3525/mmci.h
@@ -0,0 +1,123 @@
1/*
2 * linux/drivers/mmc/host/mmci.h - ARM PrimeCell MMCI PL180/1 driver
3 *
4 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10//#define MMCIPOWER 0x000
11#define MCI_PWR_OFF 0x00
12#define MCI_PWR_UP 0x02
13#define MCI_PWR_ON 0x03
14#define MCI_OD (1 << 6)
15#define MCI_ROD (1 << 7)
16
17//#define MMCICLOCK 0x004
18#define MCI_CLK_ENABLE (1 << 8)
19#define MCI_CLK_PWRSAVE (1 << 9)
20#define MCI_CLK_BYPASS (1 << 10)
21#define MCI_WIDEBUS (1 << 11)
22
23//#define MMCIARGUMENT 0x008
24//#define MMCICOMMAND 0x00c
25#define MCI_CPSM_RESPONSE (1 << 6)
26#define MCI_CPSM_LONGRSP (1 << 7)
27#define MCI_CPSM_INTERRUPT (1 << 8)
28#define MCI_CPSM_PENDING (1 << 9)
29#define MCI_CPSM_ENABLE (1 << 10)
30
31#if 0
32#define MMCIRESPCMD 0x010
33#define MMCIRESPONSE0 0x014
34#define MMCIRESPONSE1 0x018
35#define MMCIRESPONSE2 0x01c
36#define MMCIRESPONSE3 0x020
37#define MMCIDATATIMER 0x024
38#define MMCIDATALENGTH 0x028
39#define MMCIDATACTRL 0x02c
40#endif
41#define MCI_DPSM_ENABLE (1 << 0)
42#define MCI_DPSM_DIRECTION (1 << 1)
43#define MCI_DPSM_MODE (1 << 2)
44#define MCI_DPSM_DMAENABLE (1 << 3)
45
46//#define MMCIDATACNT 0x030
47//#define MMCISTATUS 0x034
48#define MCI_CMDCRCFAIL (1 << 0)
49#define MCI_DATACRCFAIL (1 << 1)
50#define MCI_CMDTIMEOUT (1 << 2)
51#define MCI_DATATIMEOUT (1 << 3)
52#define MCI_TXUNDERRUN (1 << 4)
53#define MCI_RXOVERRUN (1 << 5)
54#define MCI_CMDRESPEND (1 << 6)
55#define MCI_CMDSENT (1 << 7)
56#define MCI_DATAEND (1 << 8)
57#define MCI_DATABLOCKEND (1 << 10)
58#define MCI_CMDACTIVE (1 << 11)
59#define MCI_TXACTIVE (1 << 12)
60#define MCI_RXACTIVE (1 << 13)
61#define MCI_TXFIFOHALFEMPTY (1 << 14)
62#define MCI_RXFIFOHALFFULL (1 << 15)
63#define MCI_TXFIFOFULL (1 << 16)
64#define MCI_RXFIFOFULL (1 << 17)
65#define MCI_TXFIFOEMPTY (1 << 18)
66#define MCI_RXFIFOEMPTY (1 << 19)
67#define MCI_TXDATAAVLBL (1 << 20)
68#define MCI_RXDATAAVLBL (1 << 21)
69
70//#define MMCICLEAR 0x038
71#define MCI_CMDCRCFAILCLR (1 << 0)
72#define MCI_DATACRCFAILCLR (1 << 1)
73#define MCI_CMDTIMEOUTCLR (1 << 2)
74#define MCI_DATATIMEOUTCLR (1 << 3)
75#define MCI_TXUNDERRUNCLR (1 << 4)
76#define MCI_RXOVERRUNCLR (1 << 5)
77#define MCI_CMDRESPENDCLR (1 << 6)
78#define MCI_CMDSENTCLR (1 << 7)
79#define MCI_DATAENDCLR (1 << 8)
80#define MCI_DATABLOCKENDCLR (1 << 10)
81
82//#define MMCIMASK0 0x03c
83#define MCI_CMDCRCFAILMASK (1 << 0)
84#define MCI_DATACRCFAILMASK (1 << 1)
85#define MCI_CMDTIMEOUTMASK (1 << 2)
86#define MCI_DATATIMEOUTMASK (1 << 3)
87#define MCI_TXUNDERRUNMASK (1 << 4)
88#define MCI_RXOVERRUNMASK (1 << 5)
89#define MCI_CMDRESPENDMASK (1 << 6)
90#define MCI_CMDSENTMASK (1 << 7)
91#define MCI_DATAENDMASK (1 << 8)
92#define MCI_DATABLOCKENDMASK (1 << 10)
93#define MCI_CMDACTIVEMASK (1 << 11)
94#define MCI_TXACTIVEMASK (1 << 12)
95#define MCI_RXACTIVEMASK (1 << 13)
96#define MCI_TXFIFOHALFEMPTYMASK (1 << 14)
97#define MCI_RXFIFOHALFFULLMASK (1 << 15)
98#define MCI_TXFIFOFULLMASK (1 << 16)
99#define MCI_RXFIFOFULLMASK (1 << 17)
100#define MCI_TXFIFOEMPTYMASK (1 << 18)
101#define MCI_RXFIFOEMPTYMASK (1 << 19)
102#define MCI_TXDATAAVLBLMASK (1 << 20)
103#define MCI_RXDATAAVLBLMASK (1 << 21)
104
105#if 0
106#define MMCIMASK1 0x040
107#define MMCIFIFOCNT 0x048
108#define MMCIFIFO 0x080 /* to 0x0bc */
109#endif
110
111#define MCI_IRQENABLE \
112 (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
113 MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
114 MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
115
116/*
117 * The size of the FIFO in bytes.
118 */
119#define MCI_FIFOSIZE (16*4)
120
121#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
122
123#define NR_SG 16