blob: faa4c1f1878a2e34a0f0197cffd57840632e6011 [file] [log] [blame]
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Jens Arnold90cbd3b2004-09-28 06:23:57 +000010 * Copyright (C) 2004 by Jens Arnold
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +000011 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdbool.h>
20#include "ata.h"
Jens Arnold6f9a7eb2004-10-06 20:43:12 +000021#include "ata_mmc.h"
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +000022#include "kernel.h"
23#include "thread.h"
24#include "led.h"
25#include "sh7034.h"
26#include "system.h"
27#include "debug.h"
28#include "panic.h"
29#include "usb.h"
30#include "power.h"
31#include "string.h"
32#include "hwcompat.h"
Jörg Hohensohn00be7462004-09-11 09:06:58 +000033#include "adc.h"
Jens Arnold90cbd3b2004-09-28 06:23:57 +000034#include "bitswap.h"
35
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +000036#define SECTOR_SIZE 512
Jens Arnold90cbd3b2004-09-28 06:23:57 +000037
38/* Command definitions */
39#define CMD_GO_IDLE_STATE 0x40 /* R1 */
40#define CMD_SEND_OP_COND 0x41 /* R1 */
41#define CMD_SEND_CSD 0x49 /* R1 */
Jens Arnolddc6caf92004-10-03 23:32:09 +000042#define CMD_SEND_CID 0x4a /* R1 */
43#define CMD_STOP_TRANSMISSION 0x4c /* R1 */
44#define CMD_SEND_STATUS 0x4d /* R2 */
Jens Arnold90cbd3b2004-09-28 06:23:57 +000045#define CMD_READ_SINGLE_BLOCK 0x51 /* R1 */
46#define CMD_READ_MULTIPLE_BLOCK 0x52 /* R1 */
Jens Arnold90cbd3b2004-09-28 06:23:57 +000047#define CMD_WRITE_BLOCK 0x58 /* R1b */
48#define CMD_WRITE_MULTIPLE_BLOCK 0x59 /* R1b */
Jens Arnolddc6caf92004-10-03 23:32:09 +000049#define CMD_READ_OCR 0x7a /* R3 */
Jens Arnold90cbd3b2004-09-28 06:23:57 +000050
51/* Response formats:
52 R1 = single byte, msb=0, various error flags
53 R1b = R1 + busy token(s)
54 R2 = 2 bytes (1st byte identical to R1), additional flags
55 R3 = 5 bytes (R1 + OCR register)
56*/
57
58#define R1_PARAMETER_ERR 0x40
59#define R1_ADDRESS_ERR 0x20
60#define R1_ERASE_SEQ_ERR 0x10
61#define R1_COM_CRC_ERR 0x08
62#define R1_ILLEGAL_CMD 0x04
63#define R1_ERASE_RESET 0x02
64#define R1_IN_IDLE_STATE 0x01
65
66#define R2_OUT_OF_RANGE 0x80
67#define R2_ERASE_PARAM 0x40
68#define R2_WP_VIOLATION 0x20
69#define R2_CARD_ECC_FAIL 0x10
70#define R2_CC_ERROR 0x08
71#define R2_ERROR 0x04
72#define R2_ERASE_SKIP 0x02
73#define R2_CARD_LOCKED 0x01
74
Jens Arnolddc6caf92004-10-03 23:32:09 +000075/* Data start tokens */
76
77#define DT_START_BLOCK 0xfe
78#define DT_START_WRITE_MULTIPLE 0xfc
79#define DT_STOP_TRAN 0xfd
80
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +000081/* for compatibility */
82bool old_recorder = false; /* FIXME: get rid of this cross-dependency */
83int ata_spinup_time = 0;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +000084char ata_device = 0; /* device 0 (master) or 1 (slave) */
85int ata_io_address = 0; /* 0x300 or 0x200, only valid on recorder */
Jens Arnold90cbd3b2004-09-28 06:23:57 +000086long last_disk_activity = -1;
87
88/* private variables */
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +000089
Jens Arnolddc6caf92004-10-03 23:32:09 +000090static struct mutex mmc_mutex;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +000091
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +000092static bool initialized = false;
Jens Arnolda15386b2004-10-04 22:29:06 +000093static bool delayed_write = false;
94static unsigned char delayed_sector[SECTOR_SIZE];
95static int delayed_sector_num;
96
Jens Arnolda450e342004-10-09 01:14:55 +000097static enum {
98 SER_POLL_WRITE,
99 SER_POLL_READ,
100 SER_DISABLED
101} serial_mode;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000102
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000103static const unsigned char dummy[] = {
104 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
105};
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000106
Jens Arnolda450e342004-10-09 01:14:55 +0000107/* 2 buffers for writing, include start token and dummy crc and an extra
108 * byte to keep word alignment */
109static unsigned char sector_buffer[2][(SECTOR_SIZE+4)];
110static int current_buffer = 0;
111
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000112static tCardInfo card_info[2];
Jens Arnolda450e342004-10-09 01:14:55 +0000113static int current_card = 0;
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000114static bool last_mmc_status = false;
115static int countdown; /* for mmc switch debouncing */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000116
117/* private function declarations */
118
119static int select_card(int card_no);
120static void deselect_card(void);
121static void setup_sci1(int bitrate_register);
Jens Arnolda450e342004-10-09 01:14:55 +0000122static void set_sci1_poll_read(void);
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000123static void write_transfer(const unsigned char *buf, int len)
124 __attribute__ ((section(".icode")));
125static void read_transfer(unsigned char *buf, int len)
126 __attribute__ ((section(".icode")));
127static unsigned char poll_byte(int timeout);
Jens Arnolddc6caf92004-10-03 23:32:09 +0000128static unsigned char poll_busy(int timeout);
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000129static int send_cmd(int cmd, unsigned long parameter, unsigned char *response);
Jens Arnolda450e342004-10-09 01:14:55 +0000130static int receive_cxd(unsigned char *buf);
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000131static int initialize_card(int card_no);
Jens Arnolda450e342004-10-09 01:14:55 +0000132static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf,
133 int timeout);
134static void swapcopy_sector(const unsigned char *buf);
135static int send_sector(const unsigned char *nextbuf, int timeout);
136static int send_single_sector(const unsigned char *buf, int timeout);
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000137
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000138static void mmc_tick(void);
139
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000140/* implementation */
141
Jens Arnold5789ee92004-10-10 19:51:11 +0000142void mmc_select_clock(int card_no)
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000143{
Jens Arnold212f18f2004-10-01 17:01:40 +0000144 if (card_no == 0) /* internal */
145 or_b(0x10, &PADRH); /* set clock gate PA12 CHECKME: mask? */
146 else /* external */
147 and_b(~0x10, &PADRH); /* clear clock gate PA12 CHECKME: mask?*/
Jens Arnold5789ee92004-10-10 19:51:11 +0000148}
149
150static int select_card(int card_no)
151{
152 mmc_select_clock(card_no);
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000153 last_disk_activity = current_tick;
Jens Arnold212f18f2004-10-01 17:01:40 +0000154
Jens Arnoldde6f7992004-09-29 00:50:40 +0000155 if (!card_info[card_no].initialized)
156 {
Jens Arnold6cb79912004-09-29 01:10:32 +0000157 setup_sci1(7); /* Initial rate: 375 kbps (need <= 400 per mmc specs) */
Jens Arnoldde6f7992004-09-29 00:50:40 +0000158 write_transfer(dummy, 10); /* allow the card to synchronize */
159 while (!(SSR1 & SCI_TEND));
160 }
161
Jens Arnold212f18f2004-10-01 17:01:40 +0000162 if (card_no == 0) /* internal */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000163 and_b(~0x04, &PADRH); /* assert CS */
Jens Arnold212f18f2004-10-01 17:01:40 +0000164 else /* external */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000165 and_b(~0x02, &PADRH); /* assert CS */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000166
167 if (card_info[card_no].initialized)
168 {
169 setup_sci1(card_info[card_no].bitrate_register);
170 return 0;
171 }
172 else
173 {
174 return initialize_card(card_no);
175 }
176}
177
178static void deselect_card(void)
179{
Jens Arnoldde6f7992004-09-29 00:50:40 +0000180 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000181 or_b(0x06, &PADRH); /* deassert CS (both cards) */
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000182
183 last_disk_activity = current_tick;
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000184}
185
186static void setup_sci1(int bitrate_register)
187{
Jens Arnoldde6f7992004-09-29 00:50:40 +0000188 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000189
190 SCR1 = 0; /* disable serial port */
191 SMR1 = SYNC_MODE; /* no prescale */
192 BRR1 = bitrate_register;
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000193 SSR1 = 0;
194
Jens Arnolda450e342004-10-09 01:14:55 +0000195 SCR1 = SCI_TE; /* enable transmitter */
196 serial_mode = SER_POLL_WRITE;
197}
198
199static void set_sci1_poll_read(void)
200{
201 while(!(SSR1 & SCI_TEND)); /* wait for end of transfer */
202 SCR1 = 0; /* disable transmitter (& receiver) */
203 SCR1 = (SCI_TE|SCI_RE); /* re-enable transmitter & receiver */
204 while(!(SSR1 & SCI_TEND)); /* wait for SCI init completion (!) */
205 serial_mode = SER_POLL_READ;
206 TDR1 = 0xFF; /* send do-nothing while reading */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000207}
208
209static void write_transfer(const unsigned char *buf, int len)
210{
211 const unsigned char *buf_end = buf + len;
Jens Arnold36813082004-10-04 17:53:53 +0000212 register unsigned char data;
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000213
Jens Arnolda450e342004-10-09 01:14:55 +0000214 if (serial_mode != SER_POLL_WRITE)
215 {
216 while(!(SSR1 & SCI_TEND)); /* wait for end of transfer */
217 SCR1 = 0; /* disable transmitter & receiver */
218 SSR1 = 0; /* clear all flags */
219 SCR1 = SCI_TE; /* enable transmitter only */
220 serial_mode = SER_POLL_WRITE;
221 }
222
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000223 while (buf < buf_end)
224 {
Jens Arnold36813082004-10-04 17:53:53 +0000225 data = fliptable[(signed char)(*buf++)]; /* bitswap */
Jens Arnolda450e342004-10-09 01:14:55 +0000226 while (!(SSR1 & SCI_TDRE)); /* wait for end of transfer */
Jens Arnold36813082004-10-04 17:53:53 +0000227 TDR1 = data; /* write byte */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000228 SSR1 = 0; /* start transmitting */
229 }
230}
231
Jens Arnold36813082004-10-04 17:53:53 +0000232/* don't call this with len == 0 */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000233static void read_transfer(unsigned char *buf, int len)
234{
Jens Arnold36813082004-10-04 17:53:53 +0000235 unsigned char *buf_end = buf + len - 1;
236 register signed char data;
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000237
Jens Arnolda450e342004-10-09 01:14:55 +0000238 if (serial_mode != SER_POLL_READ)
239 set_sci1_poll_read();
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000240
Jens Arnold36813082004-10-04 17:53:53 +0000241 SSR1 = 0; /* start receiving first byte */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000242 while (buf < buf_end)
243 {
Jens Arnold36813082004-10-04 17:53:53 +0000244 while (!(SSR1 & SCI_RDRF)); /* wait for data */
245 data = RDR1; /* read byte */
246 SSR1 = 0; /* start receiving */
247 *buf++ = fliptable[data]; /* bitswap */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000248 }
Jens Arnold36813082004-10-04 17:53:53 +0000249 while (!(SSR1 & SCI_RDRF)); /* wait for last byte */
250 *buf = fliptable[(signed char)(RDR1)]; /* read & bitswap */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000251}
252
Jens Arnold06601052004-10-09 22:48:10 +0000253/* returns 0xFF on timeout, timeout is in bytes */
254static unsigned char poll_byte(int timeout)
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000255{
256 int i;
257 unsigned char data = 0; /* stop the compiler complaining */
258
Jens Arnolda450e342004-10-09 01:14:55 +0000259 if (serial_mode != SER_POLL_READ)
260 set_sci1_poll_read();
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000261
262 i = 0;
263 do {
264 SSR1 = 0; /* start receiving */
265 while (!(SSR1 & SCI_RDRF)); /* wait for data */
266 data = RDR1; /* read byte */
267 } while ((data == 0xFF) && (++i < timeout));
268
269 return fliptable[(signed char)data];
270}
271
Jens Arnold06601052004-10-09 22:48:10 +0000272/* returns 0 on timeout, timeout is in bytes */
273static unsigned char poll_busy(int timeout)
Jens Arnoldde6f7992004-09-29 00:50:40 +0000274{
275 int i;
Jens Arnold7d8598f2004-09-29 22:44:02 +0000276 unsigned char data, dummy;
Jens Arnoldde6f7992004-09-29 00:50:40 +0000277
Jens Arnolda450e342004-10-09 01:14:55 +0000278 if (serial_mode != SER_POLL_READ)
279 set_sci1_poll_read();
Jens Arnold7d8598f2004-09-29 22:44:02 +0000280
281 /* get data response */
282 SSR1 = 0; /* start receiving */
283 while (!(SSR1 & SCI_RDRF)); /* wait for data */
Jens Arnolda15386b2004-10-04 22:29:06 +0000284 data = fliptable[(signed char)(RDR1)]; /* read byte */
Jens Arnold7d8598f2004-09-29 22:44:02 +0000285
286 /* wait until the card is ready again */
Jens Arnoldde6f7992004-09-29 00:50:40 +0000287 i = 0;
288 do {
289 SSR1 = 0; /* start receiving */
290 while (!(SSR1 & SCI_RDRF)); /* wait for data */
Jens Arnold7d8598f2004-09-29 22:44:02 +0000291 dummy = RDR1; /* read byte */
292 } while ((dummy != 0xFF) && (++i < timeout));
293
Jens Arnold06601052004-10-09 22:48:10 +0000294 return (dummy == 0xFF) ? data : 0;
Jens Arnoldde6f7992004-09-29 00:50:40 +0000295}
296
Jens Arnolda450e342004-10-09 01:14:55 +0000297/* Send MMC command and get response */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000298static int send_cmd(int cmd, unsigned long parameter, unsigned char *response)
299{
Jens Arnolddc6caf92004-10-03 23:32:09 +0000300 unsigned char command[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF};
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000301
302 command[0] = cmd;
303
304 if (parameter != 0)
305 {
306 command[1] = (parameter >> 24) & 0xFF;
307 command[2] = (parameter >> 16) & 0xFF;
308 command[3] = (parameter >> 8) & 0xFF;
309 command[4] = parameter & 0xFF;
310 }
311
Jens Arnolddc6caf92004-10-03 23:32:09 +0000312 write_transfer(command, 7);
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000313
Jens Arnoldde6f7992004-09-29 00:50:40 +0000314 response[0] = poll_byte(20);
Jens Arnolda450e342004-10-09 01:14:55 +0000315
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000316 if (response[0] != 0x00)
317 {
318 write_transfer(dummy, 1);
319 return -1;
320 }
321
322 switch (cmd)
323 {
324 case CMD_SEND_CSD: /* R1 response, leave open */
325 case CMD_SEND_CID:
326 case CMD_READ_SINGLE_BLOCK:
Jens Arnolddc6caf92004-10-03 23:32:09 +0000327 case CMD_READ_MULTIPLE_BLOCK:
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000328 break;
329
330 case CMD_SEND_STATUS: /* R2 response, close with dummy */
331 read_transfer(response + 1, 1);
332 write_transfer(dummy, 1);
333 break;
334
335 case CMD_READ_OCR: /* R3 response, close with dummy */
336 read_transfer(response + 1, 4);
337 write_transfer(dummy, 1);
338 break;
339
340 default: /* R1 response, close with dummy */
341 write_transfer(dummy, 1);
342 break; /* also catches block writes */
343 }
344
345 return 0;
346}
347
Jens Arnolda450e342004-10-09 01:14:55 +0000348/* Receive CID/ CSD data (16 bytes) */
349static int receive_cxd(unsigned char *buf)
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000350{
Jens Arnolda450e342004-10-09 01:14:55 +0000351 if (poll_byte(20) != DT_START_BLOCK)
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000352 {
353 write_transfer(dummy, 1);
354 return -1; /* not start of data */
355 }
Jens Arnoldde6f7992004-09-29 00:50:40 +0000356
Jens Arnolda450e342004-10-09 01:14:55 +0000357 read_transfer(buf, 16);
358 write_transfer(dummy, 3); /* 2 bytes dontcare crc + 1 byte trailer */
359 return 0;
Jens Arnoldde6f7992004-09-29 00:50:40 +0000360}
361
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000362/* helper function to extract n (<=32) bits from an arbitrary position.
363 counting from MSB to LSB */
364unsigned long mmc_extract_bits(
365 const unsigned long *p, /* the start of the bitfield array */
366 unsigned int start, /* bit no. to start reading */
367 unsigned int size) /* how many bits to read */
368{
369 unsigned int bit_index;
370 unsigned int bits_to_use;
371 unsigned long mask;
372 unsigned long result;
373
374 if (size == 1)
375 { /* short cut */
376 return ((p[start/32] >> (31 - (start % 32))) & 1);
377 }
378
379 result = 0;
380 while (size)
381 {
382 bit_index = start % 32;
383 bits_to_use = MIN(32 - bit_index, size);
384 mask = 0xFFFFFFFF >> (32 - bits_to_use);
385
386 result <<= bits_to_use; /* start last round */
387 result |= (p[start/32] >> (32 - bits_to_use - bit_index)) & mask;
388
389 start += bits_to_use;
390 size -= bits_to_use;
391 }
392
393 return result;
394}
395
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000396static int initialize_card(int card_no)
397{
398 int i, temp;
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000399 unsigned char response[5];
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000400 tCardInfo *card = &card_info[card_no];
401
402 static const char mantissa[] = { /* *10 */
403 0, 10, 12, 13, 15, 20, 25, 30,
404 35, 40, 45, 50, 55, 60, 70, 80
405 };
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000406 static const int exponent[] = { /* use varies */
407 1, 10, 100, 1000, 10000, 100000, 1000000,
408 10000000, 100000000, 1000000000
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000409 };
410
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000411 /* switch to SPI mode */
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000412 send_cmd(CMD_GO_IDLE_STATE, 0, response);
413 if (response[0] != 0x01)
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000414 return -1; /* error response */
415
416 /* initialize card */
417 i = 0;
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000418 while (send_cmd(CMD_SEND_OP_COND, 0, response) && (++i < 200));
419 if (response[0] != 0x00)
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000420 return -2; /* not ready */
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000421
422 /* get OCR register */
423 if (send_cmd(CMD_READ_OCR, 0, response))
424 return -3;
425 card->ocr = (response[1] << 24) + (response[2] << 16)
426 + (response[3] << 8) + response[4];
427
428 /* check voltage */
429 if (!(card->ocr & 0x00100000)) /* 3.2 .. 3.3 V */
430 return -4;
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000431
432 /* get CSD register */
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000433 if (send_cmd(CMD_SEND_CSD, 0, response))
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000434 return -5;
Jens Arnolda450e342004-10-09 01:14:55 +0000435 if (receive_cxd((unsigned char*)card->csd))
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000436 return -6;
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000437
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000438 /* check block size */
439 if ((1 << mmc_extract_bits(card->csd, 44, 4)) != SECTOR_SIZE)
440 return -7;
441
442 /* max transmission speed, clock divider */
443 temp = mmc_extract_bits(card->csd, 29, 3);
444 temp = (temp > 3) ? 3 : temp;
445 card->speed = mantissa[mmc_extract_bits(card->csd, 25, 4)]
446 * exponent[temp + 4];
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000447 card->bitrate_register = (FREQ/4-1) / card->speed;
448
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000449 /* NSAC, TSAC, read timeout */
450 card->nsac = 100 * mmc_extract_bits(card->csd, 16, 8);
451 card->tsac = mantissa[mmc_extract_bits(card->csd, 9, 4)];
452 temp = mmc_extract_bits(card->csd, 13, 3);
453 card->read_timeout = ((FREQ/4) / (card->bitrate_register + 1)
454 * card->tsac / exponent[9 - temp]
455 + (10 * card->nsac));
456 card->read_timeout /= 8; /* clocks -> bytes */
457 card->tsac *= exponent[temp];
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000458
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000459 /* r2w_factor, write timeout */
460 temp = mmc_extract_bits(card->csd, 99, 3);
461 temp = (temp > 5) ? 5 : temp;
462 card->r2w_factor = 1 << temp;
463 card->write_timeout = card->read_timeout * card->r2w_factor;
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000464
465 /* switch to full speed */
466 setup_sci1(card->bitrate_register);
467
468 /* get CID register */
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000469 if (send_cmd(CMD_SEND_CID, 0, response))
470 return -8;
Jens Arnolda450e342004-10-09 01:14:55 +0000471 if (receive_cxd((unsigned char*)card->cid))
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000472 return -9;
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000473
474 card->initialized = true;
475 return 0;
476}
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000477
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000478tCardInfo *mmc_card_info(int card_no)
479{
480 tCardInfo *card = &card_info[card_no];
481
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000482 if (!card->initialized && ((card_no == 0) || mmc_detect()))
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000483 {
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000484 mutex_lock(&mmc_mutex);
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000485 select_card(card_no);
486 deselect_card();
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000487 mutex_unlock(&mmc_mutex);
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000488 }
489 return card;
490}
491
Jens Arnolda450e342004-10-09 01:14:55 +0000492/* Receive one sector with dma, possibly swapping the previously received
493 * sector in the background */
494static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf,
495 int timeout)
496{
497 if (poll_byte(timeout) != DT_START_BLOCK)
498 {
499 write_transfer(dummy, 1);
500 return -1; /* not start of data */
501 }
502
503 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
504
505 SCR1 = 0; /* disable serial */
506 SSR1 = 0; /* clear all flags */
507
508 /* setup DMA channel 2 */
509 CHCR2 = 0; /* disable */
510 SAR2 = RDR1_ADDR;
511 DAR2 = (unsigned long) inbuf;
512 DTCR2 = SECTOR_SIZE;
513 CHCR2 = 0x4601; /* fixed source address, RXI1, enable */
514 DMAOR = 0x0001;
515 SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */
516
517 /* dma receives 2 bytes more than DTCR2, but the last 2 bytes are not
518 * stored. The first extra byte is available from RDR1 after the DMA ends,
519 * the second one is lost because of the SCI overrun. However, this
520 * behaviour conveniently discards the crc. */
521
522 if (swapbuf != NULL) /* bitswap previous sector */
523 bitswap(swapbuf, SECTOR_SIZE);
524 yield(); /* be nice */
525
526 while (!(CHCR2 & 0x0002)); /* wait for end of DMA */
527 while (!(SSR1 & SCI_ORER)); /* wait for the trailing bytes */
528 SCR1 = 0;
529 serial_mode = SER_DISABLED;
530
531 write_transfer(dummy, 1); /* send trailer */
532 return 0;
533}
534
535/* copies one sector into the next-current write buffer, then bitswaps */
536static void swapcopy_sector(const unsigned char *buf)
537{
538 unsigned char *curbuf;
539
540 current_buffer ^= 1; /* toggles between 0 and 1 */
541
542 curbuf = sector_buffer[current_buffer];
543 curbuf[1] = DT_START_WRITE_MULTIPLE;
544 curbuf[(SECTOR_SIZE+2)] = curbuf[(SECTOR_SIZE+3)] = 0xFF; /* dummy crc */
545 memcpy(curbuf + 2, buf, SECTOR_SIZE);
546 bitswap(curbuf + 1, (SECTOR_SIZE+1));
547}
548
549/* Send one sector with dma from the current sector buffer, possibly preparing
550 * the next sector within the other sector buffer in the background. Use
551 * for multisector transfer only */
552static int send_sector(const unsigned char *nextbuf, int timeout)
553{
554 int ret = 0;
555
556 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
557
558 SCR1 = 0; /* disable serial */
559 SSR1 = 0; /* clear all flags */
560
561 /* setup DMA channel 2 */
562 CHCR2 = 0; /* disable */
563 SAR2 = (unsigned long)(sector_buffer[current_buffer] + 1);
564 DAR2 = TDR1_ADDR;
565 DTCR2 = (SECTOR_SIZE+3);
566 CHCR2 = 0x1701; /* fixed dest. address, TXI1, enable */
567 DMAOR = 0x0001;
568 SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */
569
570 if (nextbuf != NULL) /* prepare next sector */
571 swapcopy_sector(nextbuf);
572 yield(); /* be nice */
573
574 while (!(CHCR2 & 0x0002)); /* wait for end of DMA */
575 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
576 SCR1 = 0;
577 serial_mode = SER_DISABLED;
578
579 if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */
580 ret = -1;
581
582 write_transfer(dummy, 1);
583
584 return ret;
585}
586
587/* Send one sector with polled i/o. Use for single sector transfers only. */
588static int send_single_sector(const unsigned char *buf, int timeout)
589{
590 int ret = 0;
591 unsigned char start_token = DT_START_BLOCK;
592
593 write_transfer(&start_token, 1);
594 write_transfer(buf, SECTOR_SIZE);
595 write_transfer(dummy, 2); /* crc - dontcare */
596
597 if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */
598 ret = -1;
599
600 write_transfer(dummy, 1);
601
602 return ret;
603}
604
Jens Arnolddc6caf92004-10-03 23:32:09 +0000605int ata_read_sectors(unsigned long start,
606 int incount,
607 void* inbuf)
608{
609 int ret = 0;
610 int i;
611 unsigned long addr;
612 unsigned char response;
Jens Arnolda450e342004-10-09 01:14:55 +0000613 void *inbuf_prev = NULL;
Jens Arnolddc6caf92004-10-03 23:32:09 +0000614 tCardInfo *card = &card_info[current_card];
Jens Arnolda450e342004-10-09 01:14:55 +0000615
Jens Arnolddc6caf92004-10-03 23:32:09 +0000616 addr = start * SECTOR_SIZE;
617
618 mutex_lock(&mmc_mutex);
619 ret = select_card(current_card);
620
621 if (ret == 0)
622 {
623 if (incount == 1)
624 {
625 ret = send_cmd(CMD_READ_SINGLE_BLOCK, addr, &response);
626 if (ret == 0)
Jens Arnolda450e342004-10-09 01:14:55 +0000627 {
628 ret = receive_sector(inbuf, inbuf_prev, card->read_timeout);
629 inbuf_prev = inbuf;
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000630 last_disk_activity = current_tick;
Jens Arnolda450e342004-10-09 01:14:55 +0000631 }
Jens Arnolddc6caf92004-10-03 23:32:09 +0000632 }
633 else
634 {
635 ret = send_cmd(CMD_READ_MULTIPLE_BLOCK, addr, &response);
636 for (i = 0; (i < incount) && (ret == 0); i++)
637 {
Jens Arnolda450e342004-10-09 01:14:55 +0000638 ret = receive_sector(inbuf, inbuf_prev, card->read_timeout);
639 inbuf_prev = inbuf;
Jens Arnolddc6caf92004-10-03 23:32:09 +0000640 inbuf += SECTOR_SIZE;
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000641 last_disk_activity = current_tick;
Jens Arnolddc6caf92004-10-03 23:32:09 +0000642 }
643 if (ret == 0)
644 ret = send_cmd(CMD_STOP_TRANSMISSION, 0, &response);
645 }
Jens Arnolda450e342004-10-09 01:14:55 +0000646 if (ret == 0)
647 bitswap(inbuf_prev, SECTOR_SIZE);
Jens Arnolddc6caf92004-10-03 23:32:09 +0000648 }
649
650 deselect_card();
651 mutex_unlock(&mmc_mutex);
652
Jens Arnolda15386b2004-10-04 22:29:06 +0000653 /* only flush if reading went ok */
654 if ( (ret == 0) && delayed_write )
655 ata_flush();
656
Jens Arnolddc6caf92004-10-03 23:32:09 +0000657 return ret;
658}
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000659
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000660int ata_write_sectors(unsigned long start,
661 int count,
662 const void* buf)
663{
664 int ret = 0;
Jens Arnoldde6f7992004-09-29 00:50:40 +0000665 int i;
666 unsigned long addr;
667 unsigned char response;
668 tCardInfo *card = &card_info[current_card];
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000669
670 if (start == 0)
671 panicf("Writing on sector 0\n");
672
Jens Arnolddc6caf92004-10-03 23:32:09 +0000673 addr = start * SECTOR_SIZE;
674
675 mutex_lock(&mmc_mutex);
Jens Arnoldde6f7992004-09-29 00:50:40 +0000676 ret = select_card(current_card);
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000677
Jens Arnolddc6caf92004-10-03 23:32:09 +0000678 if (ret == 0)
Jens Arnoldde6f7992004-09-29 00:50:40 +0000679 {
Jens Arnolddc6caf92004-10-03 23:32:09 +0000680 if (count == 1)
681 {
682 ret = send_cmd(CMD_WRITE_BLOCK, addr, &response);
683 if (ret == 0)
Jens Arnolda450e342004-10-09 01:14:55 +0000684 ret = send_single_sector(buf, card->write_timeout);
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000685 last_disk_activity = current_tick;
Jens Arnolddc6caf92004-10-03 23:32:09 +0000686 }
687 else
688 {
Jens Arnolda450e342004-10-09 01:14:55 +0000689 swapcopy_sector(buf); /* prepare first sector */
Jens Arnolddc6caf92004-10-03 23:32:09 +0000690 ret = send_cmd(CMD_WRITE_MULTIPLE_BLOCK, addr, &response);
Jens Arnolda450e342004-10-09 01:14:55 +0000691 for (i = 1; (i < count) && (ret == 0); i++)
Jens Arnolddc6caf92004-10-03 23:32:09 +0000692 {
Jens Arnolddc6caf92004-10-03 23:32:09 +0000693 buf += SECTOR_SIZE;
Jens Arnolda450e342004-10-09 01:14:55 +0000694 ret = send_sector(buf, card->write_timeout);
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000695 last_disk_activity = current_tick;
Jens Arnolddc6caf92004-10-03 23:32:09 +0000696 }
697 if (ret == 0)
698 {
Jens Arnolda450e342004-10-09 01:14:55 +0000699 ret = send_sector(NULL, card->write_timeout);
700 if (ret == 0)
701 {
702 response = DT_STOP_TRAN;
703 write_transfer(&response, 1);
704 poll_busy(card->write_timeout);
705 }
Jens Arnold6f9a7eb2004-10-06 20:43:12 +0000706 last_disk_activity = current_tick;
Jens Arnolddc6caf92004-10-03 23:32:09 +0000707 }
708 }
Jens Arnoldde6f7992004-09-29 00:50:40 +0000709 }
710
711 deselect_card();
Jens Arnolddc6caf92004-10-03 23:32:09 +0000712 mutex_unlock(&mmc_mutex);
713
Jens Arnolda15386b2004-10-04 22:29:06 +0000714 /* only flush if writing went ok */
715 if ( (ret == 0) && delayed_write )
716 ata_flush();
717
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000718 return ret;
719}
720
Jens Arnolda15386b2004-10-04 22:29:06 +0000721/* While there is no spinup, the delayed write is still here to avoid
722 wearing the flash unnecessarily */
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000723extern void ata_delayed_write(unsigned long sector, const void* buf)
724{
Jens Arnolda15386b2004-10-04 22:29:06 +0000725 memcpy(delayed_sector, buf, SECTOR_SIZE);
726 delayed_sector_num = sector;
727 delayed_write = true;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000728}
729
730extern void ata_flush(void)
731{
Jens Arnolda15386b2004-10-04 22:29:06 +0000732 if ( delayed_write ) {
733 DEBUGF("ata_flush()\n");
734 delayed_write = false;
735 ata_write_sectors(delayed_sector_num, 1, delayed_sector);
736 }
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000737}
738
739void ata_spindown(int seconds)
740{
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000741 (void)seconds;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000742}
743
744bool ata_disk_is_active(void)
Jens Arnold06601052004-10-09 22:48:10 +0000745{
Jens Arnolddc6caf92004-10-03 23:32:09 +0000746 /* this is correct unless early return from write gets implemented */
747 return mmc_mutex.locked;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000748}
749
750int ata_standby(int time)
751{
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000752 (void)time;
753
Jens Arnoldfc9aada2004-10-01 21:41:44 +0000754 return 0;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000755}
756
757int ata_sleep(void)
758{
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000759 return 0;
760}
761
762void ata_spin(void)
763{
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000764}
765
Jens Arnold5789ee92004-10-10 19:51:11 +0000766bool mmc_detect(void)
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000767{
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000768 return adc_read(ADC_MMC_SWITCH) < 0x200 ? true : false;
769}
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000770
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000771static void mmc_tick(void)
772{
773 bool current_status;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000774
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000775 current_status = mmc_detect();
776
777 /* Only report when the status has changed */
778 if (current_status != last_mmc_status)
779 {
780 last_mmc_status = current_status;
781 countdown = 30;
782 }
783 else
784 {
785 /* Count down until it gets negative */
786 if (countdown >= 0)
787 countdown--;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000788
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000789 /* Report to the thread if we have had 3 identical status
790 readings in a row */
791 if (countdown == 0)
792 {
793 if (current_status)
794 {
795 queue_broadcast(SYS_MMC_INSERTED, NULL);
796 }
797 else
798 {
799 queue_broadcast(SYS_MMC_EXTRACTED, NULL);
800 card_info[1].initialized = false;
801 }
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000802 }
803 }
804}
805
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000806int ata_soft_reset(void)
807{
Jens Arnolda450e342004-10-09 01:14:55 +0000808 return 0;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000809}
810
811void ata_enable(bool on)
812{
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000813 PBCR1 &= ~0x0CF0; /* PB13, PB11 and PB10 become GPIOs, if not modified below */
Jörg Hohensohnc4b326c2004-10-01 16:57:54 +0000814 PACR2 &= ~0x4000; /* use PA7 (bridge reset) as GPIO */
Jörg Hohensohnc4e8bed2004-09-11 15:18:10 +0000815 if (on)
816 {
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000817 PBCR1 |= 0x08A0; /* as SCK1, TxD1, RxD1 */
Jens Arnoldde6f7992004-09-29 00:50:40 +0000818 IPRE &= 0x0FFF; /* disable SCI1 interrupts for the CPU */
Jörg Hohensohnc4e8bed2004-09-11 15:18:10 +0000819 }
Jens Arnoldde6f7992004-09-29 00:50:40 +0000820 and_b(~0x80, &PADRL); /* assert reset */
821 sleep(HZ/20);
822 or_b(0x80, &PADRL); /* de-assert reset */
823 sleep(HZ/20);
824 card_info[0].initialized = false;
825 card_info[1].initialized = false;
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000826}
827
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000828int ata_init(void)
829{
830 int rc = 0;
831
Jens Arnolddc6caf92004-10-03 23:32:09 +0000832 mutex_init(&mmc_mutex);
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000833
834 led(false);
835
Jörg Hohensohn00be7462004-09-11 09:06:58 +0000836 /* Port setup */
Jörg Hohensohnc4b326c2004-10-01 16:57:54 +0000837 PACR1 &= ~0x0F00; /* GPIO function for PA12, /IRQ1 for PA13 */
838 PACR1 |= 0x0400;
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000839 PADR |= 0x0680; /* set all the selects + reset high (=inactive) */
840 PAIOR |= 0x1680; /* make outputs for them and the PA12 clock gate */
841
842 PBDR |= 0x2C00; /* SCK1, TxD1 and RxD1 high when GPIO CHECKME: mask */
843 PBIOR |= 0x2000; /* SCK1 output */
844 PBIOR &= ~0x0C00; /* TxD1, RxD1 input */
Jörg Hohensohn00be7462004-09-11 09:06:58 +0000845
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000846 last_mmc_status = mmc_detect();
847 if (last_mmc_status)
Jörg Hohensohn00be7462004-09-11 09:06:58 +0000848 { /* MMC inserted */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000849 current_card = 1;
Jörg Hohensohn00be7462004-09-11 09:06:58 +0000850 }
851 else
852 { /* no MMC, use internal memory */
Jens Arnold90cbd3b2004-09-28 06:23:57 +0000853 current_card = 0;
Jörg Hohensohn00be7462004-09-11 09:06:58 +0000854 }
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000855
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000856 ata_enable(true);
Jens Arnolda450e342004-10-09 01:14:55 +0000857
Jens Arnoldf5bdf692004-10-10 00:35:19 +0000858 if ( !initialized )
859 {
860 tick_add_task(mmc_tick);
Jörg Hohensohn57ea92c2004-09-11 03:48:05 +0000861 initialized = true;
862 }
863
864 return rc;
865}
866