2004-09-11 03:48:05 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
2004-09-28 06:23:57 +00:00
|
|
|
* Copyright (C) 2004 by Jens Arnold
|
2004-09-11 03:48:05 +00:00
|
|
|
*
|
|
|
|
* All files in this archive are subject to the GNU General Public License.
|
|
|
|
* See the file COPYING in the source tree root for full license agreement.
|
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include "ata.h"
|
2004-10-06 20:43:12 +00:00
|
|
|
#include "ata_mmc.h"
|
2004-09-11 03:48:05 +00:00
|
|
|
#include "kernel.h"
|
|
|
|
#include "thread.h"
|
|
|
|
#include "led.h"
|
|
|
|
#include "sh7034.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "panic.h"
|
|
|
|
#include "usb.h"
|
|
|
|
#include "power.h"
|
|
|
|
#include "string.h"
|
|
|
|
#include "hwcompat.h"
|
2004-09-11 09:06:58 +00:00
|
|
|
#include "adc.h"
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
#include "bitswap.h"
|
|
|
|
|
2004-09-11 03:48:05 +00:00
|
|
|
#define SECTOR_SIZE 512
|
2004-09-28 06:23:57 +00:00
|
|
|
|
|
|
|
/* Command definitions */
|
|
|
|
#define CMD_GO_IDLE_STATE 0x40 /* R1 */
|
|
|
|
#define CMD_SEND_OP_COND 0x41 /* R1 */
|
|
|
|
#define CMD_SEND_CSD 0x49 /* R1 */
|
2004-10-03 23:32:09 +00:00
|
|
|
#define CMD_SEND_CID 0x4a /* R1 */
|
|
|
|
#define CMD_STOP_TRANSMISSION 0x4c /* R1 */
|
|
|
|
#define CMD_SEND_STATUS 0x4d /* R2 */
|
2004-09-28 06:23:57 +00:00
|
|
|
#define CMD_READ_SINGLE_BLOCK 0x51 /* R1 */
|
|
|
|
#define CMD_READ_MULTIPLE_BLOCK 0x52 /* R1 */
|
|
|
|
#define CMD_WRITE_BLOCK 0x58 /* R1b */
|
|
|
|
#define CMD_WRITE_MULTIPLE_BLOCK 0x59 /* R1b */
|
2004-10-03 23:32:09 +00:00
|
|
|
#define CMD_READ_OCR 0x7a /* R3 */
|
2004-09-28 06:23:57 +00:00
|
|
|
|
|
|
|
/* Response formats:
|
|
|
|
R1 = single byte, msb=0, various error flags
|
|
|
|
R1b = R1 + busy token(s)
|
|
|
|
R2 = 2 bytes (1st byte identical to R1), additional flags
|
|
|
|
R3 = 5 bytes (R1 + OCR register)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define R1_PARAMETER_ERR 0x40
|
|
|
|
#define R1_ADDRESS_ERR 0x20
|
|
|
|
#define R1_ERASE_SEQ_ERR 0x10
|
|
|
|
#define R1_COM_CRC_ERR 0x08
|
|
|
|
#define R1_ILLEGAL_CMD 0x04
|
|
|
|
#define R1_ERASE_RESET 0x02
|
|
|
|
#define R1_IN_IDLE_STATE 0x01
|
|
|
|
|
|
|
|
#define R2_OUT_OF_RANGE 0x80
|
|
|
|
#define R2_ERASE_PARAM 0x40
|
|
|
|
#define R2_WP_VIOLATION 0x20
|
|
|
|
#define R2_CARD_ECC_FAIL 0x10
|
|
|
|
#define R2_CC_ERROR 0x08
|
|
|
|
#define R2_ERROR 0x04
|
|
|
|
#define R2_ERASE_SKIP 0x02
|
|
|
|
#define R2_CARD_LOCKED 0x01
|
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
/* Data start tokens */
|
|
|
|
|
|
|
|
#define DT_START_BLOCK 0xfe
|
|
|
|
#define DT_START_WRITE_MULTIPLE 0xfc
|
|
|
|
#define DT_STOP_TRAN 0xfd
|
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
// DEBUG
|
|
|
|
#include "../../apps/screens.h"
|
2004-09-11 03:48:05 +00:00
|
|
|
|
|
|
|
/* for compatibility */
|
|
|
|
bool old_recorder = false; /* FIXME: get rid of this cross-dependency */
|
|
|
|
int ata_spinup_time = 0;
|
|
|
|
char ata_device = 0; /* device 0 (master) or 1 (slave) */
|
|
|
|
int ata_io_address = 0; /* 0x300 or 0x200, only valid on recorder */
|
2004-09-28 06:23:57 +00:00
|
|
|
long last_disk_activity = -1;
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
/* private variables */
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
static struct mutex mmc_mutex;
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
static char mmc_stack[DEFAULT_STACK_SIZE];
|
|
|
|
static const char mmc_thread_name[] = "mmc";
|
|
|
|
static struct event_queue mmc_queue;
|
2004-09-11 03:48:05 +00:00
|
|
|
static bool initialized = false;
|
2004-10-04 22:29:06 +00:00
|
|
|
static bool delayed_write = false;
|
|
|
|
static unsigned char delayed_sector[SECTOR_SIZE];
|
|
|
|
static int delayed_sector_num;
|
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
static int current_card = 0;
|
|
|
|
|
|
|
|
static const unsigned char dummy[] = {
|
|
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
|
|
|
};
|
|
|
|
|
|
|
|
static tCardInfo card_info[2];
|
|
|
|
|
|
|
|
/* private function declarations */
|
|
|
|
|
|
|
|
static int select_card(int card_no);
|
|
|
|
static void deselect_card(void);
|
|
|
|
static void setup_sci1(int bitrate_register);
|
|
|
|
static void write_transfer(const unsigned char *buf, int len)
|
|
|
|
__attribute__ ((section(".icode")));
|
|
|
|
static void read_transfer(unsigned char *buf, int len)
|
|
|
|
__attribute__ ((section(".icode")));
|
|
|
|
static unsigned char poll_byte(int timeout);
|
2004-10-03 23:32:09 +00:00
|
|
|
static unsigned char poll_busy(int timeout);
|
2004-09-28 06:23:57 +00:00
|
|
|
static int send_cmd(int cmd, unsigned long parameter, unsigned char *response);
|
|
|
|
static int receive_data(unsigned char *buf, int len, int timeout);
|
2004-10-03 23:32:09 +00:00
|
|
|
static int send_data(char start_token, const unsigned char *buf, int len,
|
|
|
|
int timeout);
|
2004-09-28 06:23:57 +00:00
|
|
|
static int initialize_card(int card_no);
|
|
|
|
|
|
|
|
/* implementation */
|
|
|
|
|
|
|
|
static int select_card(int card_no)
|
|
|
|
{
|
2004-10-01 17:01:40 +00:00
|
|
|
if (card_no == 0) /* internal */
|
|
|
|
or_b(0x10, &PADRH); /* set clock gate PA12 CHECKME: mask? */
|
|
|
|
else /* external */
|
|
|
|
and_b(~0x10, &PADRH); /* clear clock gate PA12 CHECKME: mask?*/
|
2004-10-06 20:43:12 +00:00
|
|
|
|
|
|
|
last_disk_activity = current_tick;
|
2004-10-01 17:01:40 +00:00
|
|
|
|
2004-09-29 00:50:40 +00:00
|
|
|
if (!card_info[card_no].initialized)
|
|
|
|
{
|
2004-09-29 01:10:32 +00:00
|
|
|
setup_sci1(7); /* Initial rate: 375 kbps (need <= 400 per mmc specs) */
|
2004-09-29 00:50:40 +00:00
|
|
|
write_transfer(dummy, 10); /* allow the card to synchronize */
|
|
|
|
while (!(SSR1 & SCI_TEND));
|
|
|
|
}
|
|
|
|
|
2004-10-01 17:01:40 +00:00
|
|
|
if (card_no == 0) /* internal */
|
2004-09-28 06:23:57 +00:00
|
|
|
and_b(~0x04, &PADRH); /* assert CS */
|
2004-10-01 17:01:40 +00:00
|
|
|
else /* external */
|
2004-09-28 06:23:57 +00:00
|
|
|
and_b(~0x02, &PADRH); /* assert CS */
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
if (card_info[card_no].initialized)
|
|
|
|
{
|
|
|
|
setup_sci1(card_info[card_no].bitrate_register);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return initialize_card(card_no);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void deselect_card(void)
|
|
|
|
{
|
2004-09-29 00:50:40 +00:00
|
|
|
while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
|
2004-09-28 06:23:57 +00:00
|
|
|
or_b(0x06, &PADRH); /* deassert CS (both cards) */
|
2004-10-06 20:43:12 +00:00
|
|
|
|
|
|
|
last_disk_activity = current_tick;
|
2004-09-28 06:23:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void setup_sci1(int bitrate_register)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2004-09-29 00:50:40 +00:00
|
|
|
while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
|
2004-09-28 06:23:57 +00:00
|
|
|
|
|
|
|
SCR1 = 0; /* disable serial port */
|
|
|
|
SMR1 = SYNC_MODE; /* no prescale */
|
|
|
|
BRR1 = bitrate_register;
|
|
|
|
SCR1 = SCI_CKE0;
|
|
|
|
SSR1 = 0;
|
|
|
|
|
|
|
|
for (i = 0; i <= bitrate_register; i++); /* wait at least one bit time */
|
|
|
|
|
|
|
|
or_b((SCI_TE|SCI_RE), &SCR1); /* enable transmitter & receiver */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_transfer(const unsigned char *buf, int len)
|
|
|
|
{
|
|
|
|
const unsigned char *buf_end = buf + len;
|
2004-10-04 17:53:53 +00:00
|
|
|
register unsigned char data;
|
2004-09-28 06:23:57 +00:00
|
|
|
|
|
|
|
/* TODO: DMA */
|
2004-09-29 00:50:40 +00:00
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
while (buf < buf_end)
|
|
|
|
{
|
2004-10-04 17:53:53 +00:00
|
|
|
data = fliptable[(signed char)(*buf++)]; /* bitswap */
|
2004-09-29 00:50:40 +00:00
|
|
|
while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
|
2004-10-04 17:53:53 +00:00
|
|
|
TDR1 = data; /* write byte */
|
2004-09-28 06:23:57 +00:00
|
|
|
SSR1 = 0; /* start transmitting */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-04 17:53:53 +00:00
|
|
|
/* don't call this with len == 0 */
|
2004-09-28 06:23:57 +00:00
|
|
|
static void read_transfer(unsigned char *buf, int len)
|
|
|
|
{
|
2004-10-04 17:53:53 +00:00
|
|
|
unsigned char *buf_end = buf + len - 1;
|
|
|
|
register signed char data;
|
2004-09-28 06:23:57 +00:00
|
|
|
|
|
|
|
/* TODO: DMA */
|
|
|
|
|
2004-09-29 00:50:40 +00:00
|
|
|
while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
|
2004-09-28 06:23:57 +00:00
|
|
|
TDR1 = 0xFF; /* send do-nothing data in parallel */
|
|
|
|
|
2004-10-04 17:53:53 +00:00
|
|
|
SSR1 = 0; /* start receiving first byte */
|
2004-09-28 06:23:57 +00:00
|
|
|
while (buf < buf_end)
|
|
|
|
{
|
2004-10-04 17:53:53 +00:00
|
|
|
while (!(SSR1 & SCI_RDRF)); /* wait for data */
|
|
|
|
data = RDR1; /* read byte */
|
|
|
|
SSR1 = 0; /* start receiving */
|
|
|
|
*buf++ = fliptable[data]; /* bitswap */
|
2004-09-28 06:23:57 +00:00
|
|
|
}
|
2004-10-04 17:53:53 +00:00
|
|
|
while (!(SSR1 & SCI_RDRF)); /* wait for last byte */
|
|
|
|
*buf = fliptable[(signed char)(RDR1)]; /* read & bitswap */
|
2004-09-28 06:23:57 +00:00
|
|
|
}
|
|
|
|
|
2004-10-06 20:43:12 +00:00
|
|
|
static unsigned char poll_byte(int timeout) /* timeout is in bytes */
|
2004-09-28 06:23:57 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char data = 0; /* stop the compiler complaining */
|
|
|
|
|
2004-09-29 00:50:40 +00:00
|
|
|
while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
|
2004-09-28 06:23:57 +00:00
|
|
|
TDR1 = 0xFF; /* send do-nothing data in parallel */
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
do {
|
|
|
|
SSR1 = 0; /* start receiving */
|
|
|
|
while (!(SSR1 & SCI_RDRF)); /* wait for data */
|
|
|
|
data = RDR1; /* read byte */
|
|
|
|
} while ((data == 0xFF) && (++i < timeout));
|
|
|
|
|
|
|
|
return fliptable[(signed char)data];
|
|
|
|
}
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-10-06 20:43:12 +00:00
|
|
|
static unsigned char poll_busy(int timeout) /* timeout is in bytes */
|
2004-09-29 00:50:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
2004-09-29 22:44:02 +00:00
|
|
|
unsigned char data, dummy;
|
2004-09-29 00:50:40 +00:00
|
|
|
|
|
|
|
while (!(SSR1 &SCI_TEND)); /* wait for end of transfer */
|
|
|
|
TDR1 = 0xFF; /* send do-nothing data in parallel */
|
2004-09-29 22:44:02 +00:00
|
|
|
|
|
|
|
/* get data response */
|
|
|
|
SSR1 = 0; /* start receiving */
|
|
|
|
while (!(SSR1 & SCI_RDRF)); /* wait for data */
|
2004-10-04 22:29:06 +00:00
|
|
|
data = fliptable[(signed char)(RDR1)]; /* read byte */
|
2004-09-29 22:44:02 +00:00
|
|
|
|
|
|
|
/* wait until the card is ready again */
|
2004-09-29 00:50:40 +00:00
|
|
|
i = 0;
|
|
|
|
do {
|
|
|
|
SSR1 = 0; /* start receiving */
|
|
|
|
while (!(SSR1 & SCI_RDRF)); /* wait for data */
|
2004-09-29 22:44:02 +00:00
|
|
|
dummy = RDR1; /* read byte */
|
|
|
|
} while ((dummy != 0xFF) && (++i < timeout));
|
|
|
|
|
2004-10-04 22:29:06 +00:00
|
|
|
return data;
|
2004-09-29 00:50:40 +00:00
|
|
|
}
|
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
static int send_cmd(int cmd, unsigned long parameter, unsigned char *response)
|
|
|
|
{
|
2004-10-03 23:32:09 +00:00
|
|
|
unsigned char command[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF};
|
2004-09-28 06:23:57 +00:00
|
|
|
|
|
|
|
command[0] = cmd;
|
|
|
|
|
|
|
|
if (parameter != 0)
|
|
|
|
{
|
|
|
|
command[1] = (parameter >> 24) & 0xFF;
|
|
|
|
command[2] = (parameter >> 16) & 0xFF;
|
|
|
|
command[3] = (parameter >> 8) & 0xFF;
|
|
|
|
command[4] = parameter & 0xFF;
|
|
|
|
}
|
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
write_transfer(command, 7);
|
2004-09-28 06:23:57 +00:00
|
|
|
|
2004-09-29 00:50:40 +00:00
|
|
|
response[0] = poll_byte(20);
|
2004-09-28 06:23:57 +00:00
|
|
|
|
|
|
|
if (response[0] != 0x00)
|
|
|
|
{
|
|
|
|
write_transfer(dummy, 1);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case CMD_SEND_CSD: /* R1 response, leave open */
|
|
|
|
case CMD_SEND_CID:
|
|
|
|
case CMD_READ_SINGLE_BLOCK:
|
2004-10-03 23:32:09 +00:00
|
|
|
case CMD_READ_MULTIPLE_BLOCK:
|
2004-09-28 06:23:57 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_SEND_STATUS: /* R2 response, close with dummy */
|
|
|
|
read_transfer(response + 1, 1);
|
|
|
|
write_transfer(dummy, 1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CMD_READ_OCR: /* R3 response, close with dummy */
|
|
|
|
read_transfer(response + 1, 4);
|
|
|
|
write_transfer(dummy, 1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: /* R1 response, close with dummy */
|
|
|
|
write_transfer(dummy, 1);
|
|
|
|
break; /* also catches block writes */
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int receive_data(unsigned char *buf, int len, int timeout)
|
|
|
|
{
|
|
|
|
unsigned char crc[2]; /* unused */
|
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
if (poll_byte(timeout) != DT_START_BLOCK)
|
2004-09-28 06:23:57 +00:00
|
|
|
{
|
|
|
|
write_transfer(dummy, 1);
|
|
|
|
return -1; /* not start of data */
|
|
|
|
}
|
|
|
|
|
|
|
|
read_transfer(buf, len);
|
|
|
|
read_transfer(crc, 2); /* throw away */
|
|
|
|
write_transfer(dummy, 1);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
static int send_data(char start_token, const unsigned char *buf, int len,
|
|
|
|
int timeout)
|
2004-09-29 00:50:40 +00:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
write_transfer(&start_token, 1);
|
2004-09-29 00:50:40 +00:00
|
|
|
write_transfer(buf, len);
|
|
|
|
write_transfer(dummy, 2); /* crc - dontcare */
|
|
|
|
|
|
|
|
if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
write_transfer(dummy, 1);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2004-10-06 20:43:12 +00:00
|
|
|
/* helper function to extract n (<=32) bits from an arbitrary position.
|
|
|
|
counting from MSB to LSB */
|
|
|
|
unsigned long mmc_extract_bits(
|
|
|
|
const unsigned long *p, /* the start of the bitfield array */
|
|
|
|
unsigned int start, /* bit no. to start reading */
|
|
|
|
unsigned int size) /* how many bits to read */
|
|
|
|
{
|
|
|
|
unsigned int bit_index;
|
|
|
|
unsigned int bits_to_use;
|
|
|
|
unsigned long mask;
|
|
|
|
unsigned long result;
|
|
|
|
|
|
|
|
if (size == 1)
|
|
|
|
{ /* short cut */
|
|
|
|
return ((p[start/32] >> (31 - (start % 32))) & 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
while (size)
|
|
|
|
{
|
|
|
|
bit_index = start % 32;
|
|
|
|
bits_to_use = MIN(32 - bit_index, size);
|
|
|
|
mask = 0xFFFFFFFF >> (32 - bits_to_use);
|
|
|
|
|
|
|
|
result <<= bits_to_use; /* start last round */
|
|
|
|
result |= (p[start/32] >> (32 - bits_to_use - bit_index)) & mask;
|
|
|
|
|
|
|
|
start += bits_to_use;
|
|
|
|
size -= bits_to_use;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
static int initialize_card(int card_no)
|
|
|
|
{
|
|
|
|
int i, temp;
|
2004-10-06 20:43:12 +00:00
|
|
|
unsigned char response[5];
|
2004-09-28 06:23:57 +00:00
|
|
|
tCardInfo *card = &card_info[card_no];
|
|
|
|
|
|
|
|
static const char mantissa[] = { /* *10 */
|
|
|
|
0, 10, 12, 13, 15, 20, 25, 30,
|
|
|
|
35, 40, 45, 50, 55, 60, 70, 80
|
|
|
|
};
|
2004-10-06 20:43:12 +00:00
|
|
|
static const int exponent[] = { /* use varies */
|
|
|
|
1, 10, 100, 1000, 10000, 100000, 1000000,
|
|
|
|
10000000, 100000000, 1000000000
|
2004-09-28 06:23:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* switch to SPI mode */
|
2004-10-06 20:43:12 +00:00
|
|
|
send_cmd(CMD_GO_IDLE_STATE, 0, response);
|
|
|
|
if (response[0] != 0x01)
|
2004-09-28 06:23:57 +00:00
|
|
|
return -1; /* error response */
|
|
|
|
|
|
|
|
/* initialize card */
|
|
|
|
i = 0;
|
2004-10-06 20:43:12 +00:00
|
|
|
while (send_cmd(CMD_SEND_OP_COND, 0, response) && (++i < 200));
|
|
|
|
if (response[0] != 0x00)
|
2004-09-28 06:23:57 +00:00
|
|
|
return -2; /* not ready */
|
2004-10-06 20:43:12 +00:00
|
|
|
|
|
|
|
/* get OCR register */
|
|
|
|
if (send_cmd(CMD_READ_OCR, 0, response))
|
2004-09-28 06:23:57 +00:00
|
|
|
return -3;
|
2004-10-06 20:43:12 +00:00
|
|
|
card->ocr = (response[1] << 24) + (response[2] << 16)
|
|
|
|
+ (response[3] << 8) + response[4];
|
2004-09-28 06:23:57 +00:00
|
|
|
|
2004-10-06 20:43:12 +00:00
|
|
|
/* check voltage */
|
|
|
|
if (!(card->ocr & 0x00100000)) /* 3.2 .. 3.3 V */
|
|
|
|
return -4;
|
|
|
|
|
|
|
|
/* get CSD register */
|
|
|
|
if (send_cmd(CMD_SEND_CSD, 0, response))
|
2004-09-28 06:23:57 +00:00
|
|
|
return -5;
|
2004-10-06 20:43:12 +00:00
|
|
|
if (receive_data((unsigned char*)card->csd, 16, 20))
|
|
|
|
return -6;
|
2004-09-28 06:23:57 +00:00
|
|
|
|
2004-10-06 20:43:12 +00:00
|
|
|
/* check block size */
|
|
|
|
if ((1 << mmc_extract_bits(card->csd, 44, 4)) != SECTOR_SIZE)
|
|
|
|
return -7;
|
|
|
|
|
|
|
|
/* max transmission speed, clock divider */
|
|
|
|
temp = mmc_extract_bits(card->csd, 29, 3);
|
|
|
|
temp = (temp > 3) ? 3 : temp;
|
|
|
|
card->speed = mantissa[mmc_extract_bits(card->csd, 25, 4)]
|
|
|
|
* exponent[temp + 4];
|
2004-09-28 06:23:57 +00:00
|
|
|
card->bitrate_register = (FREQ/4-1) / card->speed;
|
|
|
|
|
2004-10-06 20:43:12 +00:00
|
|
|
/* NSAC, TSAC, read timeout */
|
|
|
|
card->nsac = 100 * mmc_extract_bits(card->csd, 16, 8);
|
|
|
|
card->tsac = mantissa[mmc_extract_bits(card->csd, 9, 4)];
|
|
|
|
temp = mmc_extract_bits(card->csd, 13, 3);
|
|
|
|
card->read_timeout = ((FREQ/4) / (card->bitrate_register + 1)
|
|
|
|
* card->tsac / exponent[9 - temp]
|
|
|
|
+ (10 * card->nsac));
|
|
|
|
card->read_timeout /= 8; /* clocks -> bytes */
|
|
|
|
card->tsac *= exponent[temp];
|
|
|
|
|
|
|
|
/* r2w_factor, write timeout */
|
|
|
|
temp = mmc_extract_bits(card->csd, 99, 3);
|
|
|
|
temp = (temp > 5) ? 5 : temp;
|
|
|
|
card->r2w_factor = 1 << temp;
|
|
|
|
card->write_timeout = card->read_timeout * card->r2w_factor;
|
2004-09-28 06:23:57 +00:00
|
|
|
|
|
|
|
/* switch to full speed */
|
|
|
|
setup_sci1(card->bitrate_register);
|
|
|
|
|
|
|
|
/* get CID register */
|
2004-10-06 20:43:12 +00:00
|
|
|
if (send_cmd(CMD_SEND_CID, 0, response))
|
|
|
|
return -8;
|
|
|
|
if (receive_data((unsigned char*)card->cid, 16, 20))
|
|
|
|
return -9;
|
2004-09-28 06:23:57 +00:00
|
|
|
|
|
|
|
card->initialized = true;
|
|
|
|
return 0;
|
|
|
|
}
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-10-06 20:43:12 +00:00
|
|
|
tCardInfo *mmc_card_info(int card_no)
|
|
|
|
{
|
|
|
|
tCardInfo *card = &card_info[card_no];
|
|
|
|
|
|
|
|
if (!card->initialized)
|
|
|
|
{
|
|
|
|
select_card(card_no);
|
|
|
|
deselect_card();
|
|
|
|
}
|
|
|
|
return card;
|
|
|
|
}
|
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
int ata_read_sectors(unsigned long start,
|
|
|
|
int incount,
|
|
|
|
void* inbuf)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int i;
|
|
|
|
unsigned long addr;
|
|
|
|
unsigned char response;
|
|
|
|
tCardInfo *card = &card_info[current_card];
|
|
|
|
|
|
|
|
addr = start * SECTOR_SIZE;
|
|
|
|
|
|
|
|
mutex_lock(&mmc_mutex);
|
|
|
|
ret = select_card(current_card);
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
if (incount == 1)
|
|
|
|
{
|
|
|
|
ret = send_cmd(CMD_READ_SINGLE_BLOCK, addr, &response);
|
|
|
|
if (ret == 0)
|
|
|
|
ret = receive_data(inbuf, SECTOR_SIZE, card->read_timeout);
|
2004-10-06 20:43:12 +00:00
|
|
|
last_disk_activity = current_tick;
|
2004-10-03 23:32:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = send_cmd(CMD_READ_MULTIPLE_BLOCK, addr, &response);
|
|
|
|
for (i = 0; (i < incount) && (ret == 0); i++)
|
|
|
|
{
|
|
|
|
ret = receive_data(inbuf, SECTOR_SIZE, card->read_timeout);
|
|
|
|
inbuf += SECTOR_SIZE;
|
2004-10-06 20:43:12 +00:00
|
|
|
last_disk_activity = current_tick;
|
2004-10-03 23:32:09 +00:00
|
|
|
}
|
|
|
|
if (ret == 0)
|
|
|
|
ret = send_cmd(CMD_STOP_TRANSMISSION, 0, &response);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
deselect_card();
|
|
|
|
mutex_unlock(&mmc_mutex);
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-10-04 22:29:06 +00:00
|
|
|
/* only flush if reading went ok */
|
|
|
|
if ( (ret == 0) && delayed_write )
|
|
|
|
ata_flush();
|
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2004-09-11 03:48:05 +00:00
|
|
|
|
|
|
|
int ata_write_sectors(unsigned long start,
|
|
|
|
int count,
|
|
|
|
const void* buf)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2004-09-29 00:50:40 +00:00
|
|
|
int i;
|
|
|
|
unsigned long addr;
|
|
|
|
unsigned char response;
|
|
|
|
tCardInfo *card = &card_info[current_card];
|
2004-09-11 03:48:05 +00:00
|
|
|
|
|
|
|
if (start == 0)
|
|
|
|
panicf("Writing on sector 0\n");
|
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
addr = start * SECTOR_SIZE;
|
|
|
|
|
|
|
|
mutex_lock(&mmc_mutex);
|
2004-09-29 00:50:40 +00:00
|
|
|
ret = select_card(current_card);
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
if (ret == 0)
|
2004-09-29 00:50:40 +00:00
|
|
|
{
|
2004-10-03 23:32:09 +00:00
|
|
|
if (count == 1)
|
|
|
|
{
|
|
|
|
ret = send_cmd(CMD_WRITE_BLOCK, addr, &response);
|
|
|
|
if (ret == 0)
|
|
|
|
ret = send_data(DT_START_BLOCK, buf, SECTOR_SIZE,
|
|
|
|
card->write_timeout);
|
2004-10-06 20:43:12 +00:00
|
|
|
last_disk_activity = current_tick;
|
2004-10-03 23:32:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = send_cmd(CMD_WRITE_MULTIPLE_BLOCK, addr, &response);
|
|
|
|
for (i = 0; (i < count) && (ret == 0); i++)
|
|
|
|
{
|
|
|
|
ret = send_data(DT_START_WRITE_MULTIPLE, buf, SECTOR_SIZE,
|
|
|
|
card->write_timeout);
|
|
|
|
buf += SECTOR_SIZE;
|
2004-10-06 20:43:12 +00:00
|
|
|
last_disk_activity = current_tick;
|
2004-10-03 23:32:09 +00:00
|
|
|
}
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
response = DT_STOP_TRAN;
|
|
|
|
write_transfer(&response, 1);
|
|
|
|
poll_busy(card->write_timeout);
|
2004-10-06 20:43:12 +00:00
|
|
|
last_disk_activity = current_tick;
|
2004-10-03 23:32:09 +00:00
|
|
|
}
|
|
|
|
}
|
2004-09-29 00:50:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
deselect_card();
|
2004-10-03 23:32:09 +00:00
|
|
|
mutex_unlock(&mmc_mutex);
|
|
|
|
|
2004-10-04 22:29:06 +00:00
|
|
|
/* only flush if writing went ok */
|
|
|
|
if ( (ret == 0) && delayed_write )
|
|
|
|
ata_flush();
|
|
|
|
|
2004-09-11 03:48:05 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2004-10-04 22:29:06 +00:00
|
|
|
/* While there is no spinup, the delayed write is still here to avoid
|
|
|
|
wearing the flash unnecessarily */
|
2004-09-11 03:48:05 +00:00
|
|
|
extern void ata_delayed_write(unsigned long sector, const void* buf)
|
|
|
|
{
|
2004-10-04 22:29:06 +00:00
|
|
|
memcpy(delayed_sector, buf, SECTOR_SIZE);
|
|
|
|
delayed_sector_num = sector;
|
|
|
|
delayed_write = true;
|
2004-09-11 03:48:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
extern void ata_flush(void)
|
|
|
|
{
|
2004-10-04 22:29:06 +00:00
|
|
|
if ( delayed_write ) {
|
|
|
|
DEBUGF("ata_flush()\n");
|
|
|
|
delayed_write = false;
|
|
|
|
ata_write_sectors(delayed_sector_num, 1, delayed_sector);
|
|
|
|
}
|
2004-09-11 03:48:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ata_spindown(int seconds)
|
|
|
|
{
|
2004-09-28 06:23:57 +00:00
|
|
|
(void)seconds;
|
2004-09-11 03:48:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ata_disk_is_active(void)
|
2004-10-03 23:32:09 +00:00
|
|
|
{
|
|
|
|
/* this is correct unless early return from write gets implemented */
|
|
|
|
return mmc_mutex.locked;
|
2004-09-11 03:48:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int ata_standby(int time)
|
|
|
|
{
|
|
|
|
(void)time;
|
|
|
|
|
2004-10-01 21:41:44 +00:00
|
|
|
return 0;
|
2004-09-11 03:48:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int ata_sleep(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ata_spin(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
static void mmc_thread(void)
|
2004-09-11 03:48:05 +00:00
|
|
|
{
|
|
|
|
struct event ev;
|
2004-09-28 06:23:57 +00:00
|
|
|
|
2004-09-11 03:48:05 +00:00
|
|
|
while (1) {
|
2004-09-28 06:23:57 +00:00
|
|
|
while ( queue_empty( &mmc_queue ) ) {
|
2004-09-11 03:48:05 +00:00
|
|
|
|
|
|
|
sleep(HZ/4);
|
|
|
|
}
|
2004-09-28 06:23:57 +00:00
|
|
|
queue_wait(&mmc_queue, &ev);
|
2004-09-11 03:48:05 +00:00
|
|
|
switch ( ev.id ) {
|
|
|
|
#ifndef USB_NONE
|
|
|
|
case SYS_USB_CONNECTED:
|
|
|
|
/* Tell the USB thread that we are safe */
|
2004-09-28 06:23:57 +00:00
|
|
|
DEBUGF("mmc_thread got SYS_USB_CONNECTED\n");
|
2004-09-11 03:48:05 +00:00
|
|
|
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
|
|
|
|
|
|
|
/* Wait until the USB cable is extracted again */
|
2004-09-28 06:23:57 +00:00
|
|
|
usb_wait_for_disconnect(&mmc_queue);
|
2004-09-11 03:48:05 +00:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ata_soft_reset(void)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ata_enable(bool on)
|
|
|
|
{
|
2004-09-28 06:23:57 +00:00
|
|
|
PBCR1 &= ~0x0CF0; /* PB13, PB11 and PB10 become GPIOs, if not modified below */
|
2004-10-01 16:57:54 +00:00
|
|
|
PACR2 &= ~0x4000; /* use PA7 (bridge reset) as GPIO */
|
2004-09-11 15:18:10 +00:00
|
|
|
if (on)
|
|
|
|
{
|
2004-09-28 06:23:57 +00:00
|
|
|
PBCR1 |= 0x08A0; /* as SCK1, TxD1, RxD1 */
|
2004-09-29 00:50:40 +00:00
|
|
|
IPRE &= 0x0FFF; /* disable SCI1 interrupts for the CPU */
|
2004-09-11 15:18:10 +00:00
|
|
|
}
|
2004-09-29 00:50:40 +00:00
|
|
|
and_b(~0x80, &PADRL); /* assert reset */
|
|
|
|
sleep(HZ/20);
|
|
|
|
or_b(0x80, &PADRL); /* de-assert reset */
|
|
|
|
sleep(HZ/20);
|
|
|
|
card_info[0].initialized = false;
|
|
|
|
card_info[1].initialized = false;
|
2004-09-11 03:48:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int ata_init(void)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
|
2004-10-03 23:32:09 +00:00
|
|
|
mutex_init(&mmc_mutex);
|
2004-09-11 03:48:05 +00:00
|
|
|
|
|
|
|
led(false);
|
|
|
|
|
2004-09-11 09:06:58 +00:00
|
|
|
/* Port setup */
|
2004-10-01 16:57:54 +00:00
|
|
|
PACR1 &= ~0x0F00; /* GPIO function for PA12, /IRQ1 for PA13 */
|
|
|
|
PACR1 |= 0x0400;
|
2004-09-28 06:23:57 +00:00
|
|
|
PADR |= 0x0680; /* set all the selects + reset high (=inactive) */
|
|
|
|
PAIOR |= 0x1680; /* make outputs for them and the PA12 clock gate */
|
|
|
|
|
|
|
|
PBDR |= 0x2C00; /* SCK1, TxD1 and RxD1 high when GPIO CHECKME: mask */
|
|
|
|
PBIOR |= 0x2000; /* SCK1 output */
|
|
|
|
PBIOR &= ~0x0C00; /* TxD1, RxD1 input */
|
2004-09-11 09:06:58 +00:00
|
|
|
|
|
|
|
if(adc_read(ADC_MMC_SWITCH) < 0x200)
|
|
|
|
{ /* MMC inserted */
|
2004-09-28 06:23:57 +00:00
|
|
|
current_card = 1;
|
2004-09-11 09:06:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* no MMC, use internal memory */
|
2004-09-28 06:23:57 +00:00
|
|
|
current_card = 0;
|
2004-09-11 09:06:58 +00:00
|
|
|
}
|
2004-09-11 03:48:05 +00:00
|
|
|
|
|
|
|
ata_enable(true);
|
|
|
|
|
|
|
|
if ( !initialized ) {
|
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
queue_init(&mmc_queue);
|
2004-09-11 03:48:05 +00:00
|
|
|
|
2004-09-28 06:23:57 +00:00
|
|
|
create_thread(mmc_thread, mmc_stack,
|
|
|
|
sizeof(mmc_stack), mmc_thread_name);
|
2004-09-11 03:48:05 +00:00
|
|
|
initialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|