Remove Linux's mmci.h since the license is strict GPLv2
[kugel-rb.git] / firmware / target / arm / as3525 / ata_sd_as3525.c
blob3dea237a5dbf27127e11ae99058c212c0b2e9b5b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright © 2008 Rafaël Carré
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 /* Driver for the ARM PL180 SD/MMC controller inside AS3525 SoC */
24 #include "config.h" /* for HAVE_MULTIVOLUME */
26 #include "as3525.h"
27 #include "pl180.h"
28 #include "panic.h"
29 #include "stdbool.h"
30 #include "ata.h"
32 #define NAND_AS3525 0
33 #define SD_AS3525 1
34 static const int pl180_base[2] = { NAND_FLASH_BASE, SD_MCI_BASE };
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))
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
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)
67 #ifdef BOOTLOADER
68 #define DEBUG
69 void reset_screen(void);
70 void printf(const char *format, ...);
71 #endif
73 struct mmc_command
75 int cmd;
76 int arg;
77 int resp[4];
78 int flags;
81 static inline void mci_delay(void) { int i = 0xffff; while(i--) ; }
83 static void mci_set_clock_divider(const int drive, int divider)
85 int clock = MMC_CLOCK(drive);
87 if(divider > 1)
89 /* use divide logic */
90 clock &= ~MCI_CLOCK_BYPASS;
92 /* convert divider to MMC_CLOCK logic */
93 divider = (divider/2) - 1;
94 if(divider >= 256)
95 divider = 255;
97 else
99 /* bypass dividing logic */
100 clock |= MCI_CLOCK_BYPASS;
101 divider = 0;
104 MMC_CLOCK(drive) = clock | divider;
106 mci_delay();
109 static int send_cmd(const int drive, struct mmc_command *cmd)
111 int val, status;
113 while(MMC_STATUS(drive) & MCI_CMD_ACTIVE); /* useless */
115 if(MMC_COMMAND(drive) & MCI_COMMAND_ENABLE) /* clears existing command */
117 MMC_COMMAND(drive) = 0;
118 mci_delay();
121 val = cmd->cmd | MCI_COMMAND_ENABLE;
122 if(cmd->flags & MMC_RESP)
124 val |= MCI_COMMAND_RESPONSE;
125 if(cmd->flags & MMC_LONG_RESP)
126 val |= MCI_COMMAND_LONG_RESPONSE;
129 MMC_CLEAR(drive) = 0x7ff;
131 MMC_ARGUMENT(drive) = (cmd->flags & MMC_ARG) ? cmd->arg : 0;
132 MMC_COMMAND(drive) = val;
134 while(MMC_STATUS(drive) & MCI_CMD_ACTIVE);
136 MMC_COMMAND(drive) = 0;
137 MMC_ARGUMENT(drive) = ~0;
141 status = MMC_STATUS(drive);
142 if(cmd->flags & MMC_RESP)
144 if(status & MCI_CMD_TIMEOUT)
146 if(cmd->cmd == SEND_IF_COND)
147 break; /* SDHC test can fail */
148 panicf("Response timeout");
150 else if(status & (MCI_CMD_CRC_FAIL|MCI_CMD_RESP_END))
151 { /* resp received */
152 cmd->resp[0] = MMC_RESP0(drive);
153 if(cmd->flags & MMC_LONG_RESP)
155 cmd->resp[1] = MMC_RESP1(drive);
156 cmd->resp[2] = MMC_RESP2(drive);
157 cmd->resp[3] = MMC_RESP3(drive);
159 break;
162 else
163 if(status & MCI_CMD_SENT)
164 break;
166 } while(1);
168 MMC_CLEAR(drive) = 0x7ff;
169 return status;
172 static void sd_init_card(const int drive)
174 struct mmc_command cmd_app, cmd_op_cond, cmd_idle, cmd_if_cond;
175 int status;
176 bool sdhc;
178 #ifdef DEBUG
179 reset_screen();
180 printf("now - powered up");
181 #endif
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_CMD_SENT)
187 panicf("goto idle failed!");
188 #ifdef DEBUG
189 else
190 printf("now - idle");
191 #endif
193 mci_delay();
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;
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 */
203 cmd_op_cond.cmd = SEND_OP_COND;
204 cmd_op_cond.flags = MMC_RESP | MMC_ARG;
206 #ifdef DEBUG
207 printf("now - card powering up");
208 #endif
210 sdhc = false;
211 status = send_cmd(drive, &cmd_if_cond);
212 if(status & (MCI_CMD_CRC_FAIL|MCI_CMD_RESP_END))
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
221 #ifdef DEBUG
222 else
223 printf("cmd_if_cond stat: 0x%x",status);
225 printf("%s Capacity",sdhc?"High":"Normal");
226 mci_delay();
227 mci_delay();
228 mci_delay();
229 #endif
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_CMD_CRC_FAIL|MCI_CMD_RESP_END)) ||
244 !(cmd_app.resp[0] & (1<<5)) )
246 panicf("app_cmd failed");
249 cmd_op_cond.arg = sdhc ? 0x40FF8000 : (8<<0x14); /* ocr */
250 status = send_cmd(drive, &cmd_op_cond);
251 if(!(status & (MCI_CMD_CRC_FAIL|MCI_CMD_RESP_END)))
252 panicf("cmd_op_cond failed");
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 */
259 #ifdef DEBUG
260 printf("now - card ready !");
261 #endif
264 static void init_pl180_controller(const int drive)
266 MMC_COMMAND(drive) = MMC_DATACTRL(drive) = 0;
267 MMC_CLEAR(drive) = 0x7ff;
269 MMC_MASK0(drive) = MMC_MASK1(drive) = 0; /* disable all interrupts */
271 MMC_POWER(drive) = MCI_POWER_UP|(10 /*voltage*/ << 2); /* use OF voltage */
272 mci_delay();
274 MMC_POWER(drive) |= MCI_POWER_ON;
275 mci_delay();
277 MMC_SELECT(drive) = 0;
279 MMC_CLOCK(drive) = MCI_CLOCK_ENABLE;
280 MMC_CLOCK(drive) &= ~MCI_CLOCK_POWERSAVE;
282 /* set MCLK divider */
283 mci_set_clock_divider(drive, 200);
286 int ata_init(void)
288 /* reset peripherals */
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;
296 CCU_SRL = CCU_SRL_MAGIC_NUMBER;
297 CCU_SRL = 0;
299 GPIOC_DIR &= ~(1<<1);
300 if(GPIOC_PIN(1))
301 CCU_SPARE1 |= 4; /* sets bit 2 of undocumented register */
302 else
303 CCU_SPARE1 &= ~4; /* or clear it */
305 CGU_IDE = (1<<7)|(1<<6); /* enable, 24MHz clock */
306 CGU_MEMSTICK = (1<<8); /* enable, 24MHz clock */
308 CGU_PERI |= CGU_NAF_CLOCK_ENABLE;
309 #ifdef HAVE_MULTIVOLUME
310 CGU_PERI |= CGU_MCI_CLOCK_ENABLE;
311 #endif
313 CCU_IO &= ~8; /* bits 3:2 = 01, xpd is SD interface */
314 CCU_IO |= 4;
316 init_pl180_controller(NAND_AS3525);
317 sd_init_card(NAND_AS3525);
319 #ifdef HAVE_MULTIVOLUME
320 init_pl180_controller(SD_AS3525);
321 sd_init_card(SD_AS3525);
322 #endif
324 return 0;
327 int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf)
329 (void)start;
330 (void)count;
331 (void)buf;
332 return 0; /* TODO */
335 int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf)
337 (void)start;
338 (void)count;
339 (void)buf;
340 return 0; /* TODO */