summaryrefslogtreecommitdiffstats
path: root/firmware/target/sh/archos/ondio/ata_mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/sh/archos/ondio/ata_mmc.c')
-rw-r--r--firmware/target/sh/archos/ondio/ata_mmc.c978
1 files changed, 0 insertions, 978 deletions
diff --git a/firmware/target/sh/archos/ondio/ata_mmc.c b/firmware/target/sh/archos/ondio/ata_mmc.c
deleted file mode 100644
index f252e1c4ce..0000000000
--- a/firmware/target/sh/archos/ondio/ata_mmc.c
+++ /dev/null
@@ -1,978 +0,0 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id$
- *
- * Copyright (C) 2004 by Jens Arnold
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include "config.h"
-#include "ata_mmc.h"
-#include "sdmmc.h"
-#include "kernel.h"
-#include "led.h"
-#include "sh7034.h"
-#include "system.h"
-#include "debug.h"
-#include "panic.h"
-#include "power.h"
-#include "string.h"
-#include "hwcompat.h"
-#include "adc.h"
-#include "bitswap.h"
-#include "storage.h"
-
-
-#ifdef HAVE_MULTIDRIVE
-#define MMC_NUM_DRIVES 2
-#else
-#define MMC_NUM_DRIVES 1
-#endif
-
-#define BLOCK_SIZE 512 /* fixed */
-
-/* Command definitions */
-#define CMD_GO_IDLE_STATE 0x40 /* R1 */
-#define CMD_SEND_OP_COND 0x41 /* R1 */
-#define CMD_SEND_CSD 0x49 /* R1 */
-#define CMD_SEND_CID 0x4a /* R1 */
-#define CMD_STOP_TRANSMISSION 0x4c /* R1 */
-#define CMD_SEND_STATUS 0x4d /* R2 */
-#define CMD_SET_BLOCKLEN 0x50 /* R1 */
-#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 */
-#define CMD_READ_OCR 0x7a /* R3 */
-
-/* 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
-
-/* Data start tokens */
-
-#define DT_START_BLOCK 0xfe
-#define DT_START_WRITE_MULTIPLE 0xfc
-#define DT_STOP_TRAN 0xfd
-
-/* for compatibility */
-static long last_disk_activity = -1;
-
-/* private variables */
-
-#ifdef CONFIG_STORAGE_MULTI
-static int mmc_first_drive = 0;
-#else
-#define mmc_first_drive 0
-#endif
-
-static struct mutex mmc_mutex SHAREDBSS_ATTR;
-
-static bool initialized = false;
-static bool new_mmc_circuit;
-
-static enum {
- MMC_UNKNOWN,
- MMC_UNTOUCHED,
- MMC_TOUCHED
-} mmc_status = MMC_UNKNOWN;
-
-static enum {
- SER_POLL_WRITE,
- SER_POLL_READ,
- SER_DISABLED
-} serial_mode;
-
-static const unsigned char dummy[] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-/* 2 buffers used alternatively for writing, including start token,
- * dummy CRC and an extra byte to keep word alignment. */
-static unsigned char write_buffer[2][BLOCK_SIZE+4];
-static int current_buffer = 0;
-static const unsigned char *send_block_addr = NULL;
-
-static tCardInfo card_info[2];
-#ifndef HAVE_MULTIDRIVE
-static int current_card = 0;
-#endif
-static bool last_mmc_status = false;
-static int countdown = -1; /* for mmc switch debouncing. -1 because the
- countdown should not happen if the card
- is inserted at boot */
-static bool usb_activity; /* monitoring the USB bridge */
-static long last_usb_activity;
-
-/* private function declarations */
-
-static int select_card(int card_no);
-static void deselect_card(void);
-static void setup_sci1(int bitrate_register);
-static void set_sci1_poll_read(void);
-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(long timeout);
-static unsigned char poll_busy(long timeout);
-static unsigned char send_cmd(int cmd, unsigned long parameter, void *data);
-static int receive_cxd(unsigned char *buf);
-static int initialize_card(int card_no);
-static int receive_block(unsigned char *inbuf, long timeout);
-static void send_block_prepare(void);
-static int send_block_send(unsigned char start_token, long timeout,
- bool prepare_next);
-static void mmc_tick(void);
-
-/* implementation */
-
-static void enable_controller(bool on)
-{
- PBCR1 &= ~0x0CF0; /* PB13, PB11 and PB10 become GPIO,
- * if not modified below */
- if (on)
- PBCR1 |= 0x08A0; /* as SCK1, TxD1, RxD1 */
-
- and_b(~0x80, &PADRL); /* assert flash reset */
- sleep(HZ/100);
- or_b(0x80, &PADRL); /* de-assert flash reset */
- sleep(HZ/100);
- card_info[0].initialized = false;
- card_info[1].initialized = false;
-}
-
-void mmc_enable_int_flash_clock(bool on)
-{
- /* Internal flash clock is enabled by setting PA12 high with the new
- * clock circuit, and by setting it low with the old clock circuit */
- if (on ^ new_mmc_circuit)
- and_b(~0x10, &PADRH); /* clear clock gate PA12 */
- else
- or_b(0x10, &PADRH); /* set clock gate PA12 */
-}
-
-static int select_card(int card_no)
-{
- mutex_lock(&mmc_mutex);
- led(true);
- last_disk_activity = current_tick;
-
- mmc_enable_int_flash_clock(card_no == 0);
-
- if (!card_info[card_no].initialized)
- {
- setup_sci1(7); /* Initial rate: 375 kbps (need <= 400 per mmc specs) */
- write_transfer(dummy, 10); /* allow the card to synchronize */
- while (!(SSR1 & SCI_TEND));
- }
-
- if (card_no == 0) /* internal */
- and_b(~0x04, &PADRH); /* assert CS */
- else /* external */
- and_b(~0x02, &PADRH); /* assert CS */
-
- 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)
-{
- while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
- or_b(0x06, &PADRH); /* deassert CS (both cards) */
-
- led(false);
- mutex_unlock(&mmc_mutex);
- last_disk_activity = current_tick;
-}
-
-static void setup_sci1(int bitrate_register)
-{
- while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
-
- SCR1 = 0; /* disable serial port */
- SMR1 = SYNC_MODE; /* no prescale */
- BRR1 = bitrate_register;
- SSR1 = 0;
-
- SCR1 = SCI_TE; /* enable transmitter */
- serial_mode = SER_POLL_WRITE;
-}
-
-static void set_sci1_poll_read(void)
-{
- while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
- SCR1 = 0; /* disable transmitter (& receiver) */
- SCR1 = (SCI_TE|SCI_RE); /* re-enable transmitter & receiver */
- while (!(SSR1 & SCI_TEND)); /* wait for SCI init completion (!) */
- serial_mode = SER_POLL_READ;
- TDR1 = 0xFF; /* send do-nothing while reading */
-}
-
-static void write_transfer(const unsigned char *buf, int len)
-{
- const unsigned char *buf_end = buf + len;
- register unsigned char data;
-
- if (serial_mode != SER_POLL_WRITE)
- {
- while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
- SCR1 = 0; /* disable transmitter & receiver */
- SSR1 = 0; /* clear all flags */
- SCR1 = SCI_TE; /* enable transmitter only */
- serial_mode = SER_POLL_WRITE;
- }
-
- while (buf < buf_end)
- {
- data = fliptable[(signed char)(*buf++)]; /* bitswap */
- while (!(SSR1 & SCI_TDRE)); /* wait for end of transfer */
- TDR1 = data; /* write byte */
- SSR1 = 0; /* start transmitting */
- }
-}
-
-/* don't call this with len == 0 */
-static void read_transfer(unsigned char *buf, int len)
-{
- unsigned char *buf_end = buf + len - 1;
- register signed char data;
-
- if (serial_mode != SER_POLL_READ)
- set_sci1_poll_read();
-
- SSR1 = 0; /* start receiving first byte */
- while (buf < buf_end)
- {
- while (!(SSR1 & SCI_RDRF)); /* wait for data */
- data = RDR1; /* read byte */
- SSR1 = 0; /* start receiving */
- *buf++ = fliptable[data]; /* bitswap */
- }
- while (!(SSR1 & SCI_RDRF)); /* wait for last byte */
- *buf = fliptable[(signed char)(RDR1)]; /* read & bitswap */
-}
-
-/* returns 0xFF on timeout, timeout is in bytes */
-static unsigned char poll_byte(long timeout)
-{
- long i;
- unsigned char data = 0; /* stop the compiler complaining */
-
- if (serial_mode != SER_POLL_READ)
- set_sci1_poll_read();
-
- 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];
-}
-
-/* returns 0 on timeout, timeout is in bytes */
-static unsigned char poll_busy(long timeout)
-{
- long i;
- unsigned char data, dummy;
-
- if (serial_mode != SER_POLL_READ)
- set_sci1_poll_read();
-
- /* get data response */
- SSR1 = 0; /* start receiving */
- while (!(SSR1 & SCI_RDRF)); /* wait for data */
- data = fliptable[(signed char)(RDR1)]; /* read byte */
-
- /* wait until the card is ready again */
- i = 0;
- do {
- SSR1 = 0; /* start receiving */
- while (!(SSR1 & SCI_RDRF)); /* wait for data */
- dummy = RDR1; /* read byte */
- } while ((dummy != 0xFF) && (++i < timeout));
-
- return (dummy == 0xFF) ? data : 0;
-}
-
-/* Send MMC command and get response. Returns R1 byte directly.
- * Returns further R2 or R3 bytes in *data (can be NULL for other commands) */
-static unsigned char send_cmd(int cmd, unsigned long parameter, void *data)
-{
- static struct {
- unsigned char cmd;
- unsigned long parameter;
- const unsigned char crc7; /* fixed, valid for CMD0 only */
- const unsigned char trailer;
- } __attribute__((packed)) command = {0x40, 0, 0x95, 0xFF};
-
- unsigned char ret;
-
- command.cmd = cmd;
- command.parameter = htobe32(parameter);
-
- write_transfer((unsigned char *)&command, sizeof(command));
-
- ret = poll_byte(20);
-
- switch (cmd)
- {
- case CMD_SEND_CSD: /* R1 response, leave open */
- case CMD_SEND_CID:
- case CMD_READ_SINGLE_BLOCK:
- case CMD_READ_MULTIPLE_BLOCK:
- return ret;
-
- case CMD_SEND_STATUS: /* R2 response, close with dummy */
- read_transfer(data, 1);
- break;
-
- case CMD_READ_OCR: /* R3 response, close with dummy */
- read_transfer(data, 4);
- break;
-
- default: /* R1 response, close with dummy */
- break; /* also catches block writes */
- }
- write_transfer(dummy, 1);
- return ret;
-}
-
-/* Receive CID/ CSD data (16 bytes) */
-static int receive_cxd(unsigned char *buf)
-{
- if (poll_byte(20) != DT_START_BLOCK)
- {
- write_transfer(dummy, 1);
- return -1; /* not start of data */
- }
-
- read_transfer(buf, 16);
- write_transfer(dummy, 3); /* 2 bytes dontcare crc + 1 byte trailer */
- return 0;
-}
-
-
-static int initialize_card(int card_no)
-{
- int rc, i;
- int blk_exp, ts_exp, taac_exp;
- 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
- };
- static const int exponent[] = { /* use varies */
- 1, 10, 100, 1000, 10000, 100000, 1000000,
- 10000000, 100000000, 1000000000
- };
-
- if (card_no == 1)
- mmc_status = MMC_TOUCHED;
-
- /* switch to SPI mode */
- if (send_cmd(CMD_GO_IDLE_STATE, 0, NULL) != 0x01)
- return -1; /* error or no response */
-
- /* initialize card */
- for (i = HZ;;) /* try for 1 second*/
- {
- sleep(1);
- if (send_cmd(CMD_SEND_OP_COND, 0, NULL) == 0)
- break;
- if (--i <= 0)
- return -2; /* timeout */
- }
-
- /* get OCR register */
- if (send_cmd(CMD_READ_OCR, 0, &card->ocr))
- return -3;
- card->ocr = betoh32(card->ocr); /* no-op on big endian */
-
- /* check voltage */
- if (!(card->ocr & 0x00100000)) /* 3.2 .. 3.3 V */
- return -4;
-
- /* get CSD register */
- if (send_cmd(CMD_SEND_CSD, 0, NULL))
- return -5;
- rc = receive_cxd((unsigned char*)card->csd);
- if (rc)
- return rc * 10 - 5;
-
- blk_exp = card_extract_bits(card->csd, 83, 4);
- if (blk_exp < 9) /* block size < 512 bytes not supported */
- return -6;
-
- card->numblocks = (card_extract_bits(card->csd, 73, 12) + 1)
- << (card_extract_bits(card->csd, 49, 3) + 2 + blk_exp - 9);
- card->blocksize = BLOCK_SIZE;
-
- /* max transmission speed, clock divider */
- ts_exp = card_extract_bits(card->csd, 98, 3);
- ts_exp = (ts_exp > 3) ? 3 : ts_exp;
- card->speed = mantissa[card_extract_bits(card->csd, 102, 4)]
- * exponent[ts_exp + 4];
- card->bitrate_register = (FREQ/4-1) / card->speed;
-
- /* NSAC, TAAC, read timeout */
- card->nsac = 100 * card_extract_bits(card->csd, 111, 8);
- card->taac = mantissa[card_extract_bits(card->csd, 118, 4)];
- taac_exp = card_extract_bits(card->csd, 114, 3);
- card->read_timeout = ((FREQ/4) / (card->bitrate_register + 1)
- * card->taac / exponent[9 - taac_exp]
- + (10 * card->nsac));
- card->read_timeout /= 8; /* clocks -> bytes */
- card->taac = card->taac * exponent[taac_exp] / 10;
-
- /* r2w_factor, write timeout */
- card->r2w_factor = BIT_N(card_extract_bits(card->csd, 28, 3));
- card->write_timeout = card->read_timeout * card->r2w_factor;
-
- if (card->r2w_factor > 32) /* Such cards often need extra read delay */
- card->read_timeout *= 4;
-
- /* switch to full speed */
- setup_sci1(card->bitrate_register);
-
- /* always use 512 byte blocks */
- if (send_cmd(CMD_SET_BLOCKLEN, BLOCK_SIZE, NULL))
- return -7;
-
- /* get CID register */
- if (send_cmd(CMD_SEND_CID, 0, NULL))
- return -8;
- rc = receive_cxd((unsigned char*)card->cid);
- if (rc)
- return rc * 10 - 8;
-
- card->initialized = true;
- return 0;
-}
-
-tCardInfo *mmc_card_info(int card_no)
-{
- tCardInfo *card = &card_info[card_no];
-
- if (!card->initialized && ((card_no == 0) || mmc_detect()))
- {
- select_card(card_no);
- deselect_card();
- }
- return card;
-}
-
-/* Receive one block with DMA and bitswap it (chasing bitswap). */
-static int receive_block(unsigned char *inbuf, long timeout)
-{
- unsigned long buf_end;
-
- if (poll_byte(timeout) != DT_START_BLOCK)
- {
- write_transfer(dummy, 1);
- return -1; /* not start of data */
- }
-
- while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
-
- SCR1 = 0; /* disable serial */
- SSR1 = 0; /* clear all flags */
-
- /* setup DMA channel 0 */
- CHCR0 = 0; /* disable */
- SAR0 = RDR1_ADDR;
- DAR0 = (unsigned long) inbuf;
- DTCR0 = BLOCK_SIZE;
- CHCR0 = 0x4601; /* fixed source address, RXI1, enable */
- DMAOR = 0x0001;
- SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */
-
- /* DMA receives 2 bytes more than DTCR2, but the last 2 bytes are not
- * stored. The first extra byte is available from RDR1 after the DMA ends,
- * the second one is lost because of the SCI overrun. However, this
- * behaviour conveniently discards the crc. */
-
- yield(); /* be nice */
-
- /* Bitswap received data, chasing the DMA pointer */
- buf_end = (unsigned long)inbuf + BLOCK_SIZE;
- do
- {
- /* Call bitswap whenever (a multiple of) 8 bytes are
- * available (value optimised by experimentation). */
- int swap_now = (DAR0 - (unsigned long)inbuf) & ~0x00000007;
- if (swap_now)
- {
- bitswap(inbuf, swap_now);
- inbuf += swap_now;
- }
- }
- while ((unsigned long)inbuf < buf_end);
-
- while (!(CHCR0 & 0x0002)); /* wait for end of DMA */
- while (!(SSR1 & SCI_ORER)); /* wait for the trailing bytes */
- SCR1 = 0;
- serial_mode = SER_DISABLED;
-
- write_transfer(dummy, 1); /* send trailer */
- last_disk_activity = current_tick;
- return 0;
-}
-
-/* Prepare a block for sending by copying it to the next write buffer
- * and bitswapping it. */
-static void send_block_prepare(void)
-{
- unsigned char *dest;
-
- current_buffer ^= 1; /* toggle buffer */
- dest = write_buffer[current_buffer] + 2;
-
- memcpy(dest, send_block_addr, BLOCK_SIZE);
- bitswap(dest, BLOCK_SIZE);
-
- send_block_addr += BLOCK_SIZE;
-}
-
-/* Send one block with DMA from the current write buffer, possibly preparing
- * the next block within the next write buffer in the background. */
-static int send_block_send(unsigned char start_token, long timeout,
- bool prepare_next)
-{
- int rc = 0;
- unsigned char *curbuf = write_buffer[current_buffer];
-
- curbuf[1] = fliptable[(signed char)start_token];
- *(unsigned short *)(curbuf + BLOCK_SIZE + 2) = 0xFFFF;
-
- while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
-
- SCR1 = 0; /* disable serial */
- SSR1 = 0; /* clear all flags */
-
- /* setup DMA channel 0 */
- CHCR0 = 0; /* disable */
- SAR0 = (unsigned long)(curbuf + 1);
- DAR0 = TDR1_ADDR;
- DTCR0 = BLOCK_SIZE + 3; /* start token + block + dummy crc */
- CHCR0 = 0x1701; /* fixed dest. address, TXI1, enable */
- DMAOR = 0x0001;
- SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */
-
- if (prepare_next)
- send_block_prepare();
- yield(); /* be nice */
-
- while (!(CHCR0 & 0x0002)); /* wait for end of DMA */
- while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
- SCR1 = 0;
- serial_mode = SER_DISABLED;
-
- if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */
- rc = -1;
-
- write_transfer(dummy, 1);
- last_disk_activity = current_tick;
-
- return rc;
-}
-
-int mmc_read_sectors(IF_MD(int drive,)
- unsigned long start,
- int incount,
- void* inbuf)
-{
- int rc = 0;
- int lastblock = 0;
- unsigned long end_block;
- tCardInfo *card;
-#ifndef HAVE_MULTIDRIVE
- int drive = current_card;
-#endif
-
- card = &card_info[drive];
- rc = select_card(drive);
- if (rc)
- {
- rc = rc * 10 - 1;
- goto error;
- }
-
- end_block = start + incount;
- if (end_block > card->numblocks)
- {
- rc = -2;
- goto error;
- }
-
- /* Some cards don't like reading the very last block with
- * CMD_READ_MULTIPLE_BLOCK, so make sure this block is always
- * read with CMD_READ_SINGLE_BLOCK. */
- if (end_block == card->numblocks)
- lastblock = 1;
-
- if (incount > 1)
- {
- /* MMC4.2: make multiplication conditional */
- if (send_cmd(CMD_READ_MULTIPLE_BLOCK, start * BLOCK_SIZE, NULL))
- {
- rc = -3;
- goto error;
- }
- while (--incount >= lastblock)
- {
- rc = receive_block(inbuf, card->read_timeout);
- if (rc)
- {
- /* If an error occurs during multiple block reading, the
- * host still needs to send CMD_STOP_TRANSMISSION */
- send_cmd(CMD_STOP_TRANSMISSION, 0, NULL);
- rc = rc * 10 - 4;
- goto error;
- }
- inbuf += BLOCK_SIZE;
- start++;
- /* ^^ necessary for the abovementioned last block special case */
- }
- if (send_cmd(CMD_STOP_TRANSMISSION, 0, NULL))
- {
- rc = -5;
- goto error;
- }
- }
- if (incount > 0)
- {
- /* MMC4.2: make multiplication conditional */
- if (send_cmd(CMD_READ_SINGLE_BLOCK, start * BLOCK_SIZE, NULL))
- {
- rc = -6;
- goto error;
- }
- rc = receive_block(inbuf, card->read_timeout);
- if (rc)
- {
- rc = rc * 10 - 7;
- goto error;
- }
- }
-
- error:
-
- deselect_card();
-
- return rc;
-}
-
-int mmc_write_sectors(IF_MD(int drive,)
- unsigned long start,
- int count,
- const void* buf)
-{
- int rc = 0;
- int write_cmd;
- unsigned char start_token;
- tCardInfo *card;
-#ifndef HAVE_MULTIDRIVE
- int drive = current_card;
-#endif
-
- card = &card_info[drive];
- rc = select_card(drive);
- if (rc)
- {
- rc = rc * 10 - 1;
- goto error;
- }
-
- if (start + count > card->numblocks)
- panicf("Writing past end of card");
-
- send_block_addr = buf;
- send_block_prepare();
-
- if (count > 1)
- {
- write_cmd = CMD_WRITE_MULTIPLE_BLOCK;
- start_token = DT_START_WRITE_MULTIPLE;
- }
- else
- {
- write_cmd = CMD_WRITE_BLOCK;
- start_token = DT_START_BLOCK;
- }
- /* MMC4.2: make multiplication conditional */
- if (send_cmd(write_cmd, start * BLOCK_SIZE, NULL))
- {
- rc = -2;
- goto error;
- }
- while (--count >= 0)
- {
- rc = send_block_send(start_token, card->write_timeout, count > 0);
- if (rc)
- {
- rc = rc * 10 - 3;
- break;
- /* If an error occurs during multiple block writing,
- * the STOP_TRAN token still needs to be sent. */
- }
- }
- if (write_cmd == CMD_WRITE_MULTIPLE_BLOCK)
- {
- static const unsigned char stop_tran = DT_STOP_TRAN;
- write_transfer(&stop_tran, 1);
- poll_busy(card->write_timeout);
- }
-
- error:
-
- deselect_card();
-
- return rc;
-}
-
-bool mmc_disk_is_active(void)
-{
- /* this is correct unless early return from write gets implemented */
- return mutex_test(&mmc_mutex);
-}
-
-bool mmc_detect(void)
-{
- return (adc_read(ADC_MMC_SWITCH) < 0x200);
-}
-
-bool mmc_touched(void)
-{
- if (mmc_status == MMC_UNKNOWN) /* try to detect */
- {
- mutex_lock(&mmc_mutex);
- setup_sci1(7); /* safe value */
- and_b(~0x02, &PADRH); /* assert CS */
- if (send_cmd(CMD_SEND_OP_COND, 0, NULL) == 0xFF)
- mmc_status = MMC_UNTOUCHED;
- else
- mmc_status = MMC_TOUCHED;
-
- deselect_card();
- }
- return mmc_status == MMC_TOUCHED;
-}
-
-bool mmc_usb_active(int delayticks)
-{
- /* reading "inactive" is delayed by user-supplied monoflop value */
- return (usb_activity ||
- TIME_BEFORE(current_tick, last_usb_activity + delayticks));
-}
-
-static void mmc_tick(void)
-{
- bool current_status;
-
- if (new_mmc_circuit)
- /* USB bridge activity is 0 on idle, ~527 on active */
- current_status = adc_read(ADC_USB_ACTIVE) > 0x100;
- else
- current_status = adc_read(ADC_USB_ACTIVE) < 0x190;
-
- if (!current_status && usb_activity)
- last_usb_activity = current_tick;
- usb_activity = current_status;
-
- current_status = mmc_detect();
- /* Only report when the status has changed */
- if (current_status != last_mmc_status)
- {
- last_mmc_status = current_status;
- countdown = HZ/3;
- }
- else
- {
- /* Count down until it gets negative */
- if (countdown >= 0)
- countdown--;
-
- if (countdown == 0)
- {
- if (current_status)
- {
- queue_broadcast(SYS_HOTSWAP_INSERTED, mmc_first_drive + 1);
- }
- else
- {
- queue_broadcast(SYS_HOTSWAP_EXTRACTED, mmc_first_drive + 1);
- mmc_status = MMC_UNTOUCHED;
- card_info[1].initialized = false;
- }
- }
- }
-}
-
-void mmc_enable(bool on)
-{
- mutex_lock(&mmc_mutex);
- enable_controller(on);
- mutex_unlock(&mmc_mutex);
-}
-
-int mmc_init(void)
-{
- int rc = 0;
-
- if (!initialized)
- mutex_init(&mmc_mutex);
-
- mutex_lock(&mmc_mutex);
- led(false);
-
- last_mmc_status = mmc_detect();
-#ifndef HAVE_MULTIDRIVE
- /* Use MMC if inserted, internal flash otherwise */
- current_card = last_mmc_status ? 1 : 0;
-#endif
-
- if (!initialized)
- {
- if (!last_mmc_status)
- mmc_status = MMC_UNTOUCHED;
-
- /* Port setup */
- PACR1 &= ~0x0F3C; /* GPIO function for PA13 (flash busy), PA12
- * (clk gate), PA10 (flash CS), PA9 (MMC CS) */
- PACR2 &= ~0x4000; /* GPIO for PA7 (flash reset) */
- PADR |= 0x0680; /* set all the selects + reset high (=inactive) */
- PAIOR |= 0x1680; /* make outputs for them and the PA12 clock gate */
-
- PBCR1 &= ~0x0CF0; /* GPIO function for PB13, PB11 and PB10 */
- PBDR |= 0x2C00; /* SCK1, TxD1 and RxD1 high in GPIO */
- PBIOR |= 0x2000; /* SCK1 output */
- PBIOR &= ~0x0C00; /* TxD1, RxD1 input */
-
- IPRE &= 0x0FFF; /* disable SCI1 interrupts for the CPU */
-
- new_mmc_circuit = ((HW_MASK & MMC_CLOCK_POLARITY) != 0);
- tick_add_task(mmc_tick);
- initialized = true;
- }
- enable_controller(true);
-
- mutex_unlock(&mmc_mutex);
- return rc;
-}
-
-long mmc_last_disk_activity(void)
-{
- return last_disk_activity;
-}
-
-#ifdef STORAGE_GET_INFO
-void mmc_get_info(IF_MD(int drive,) struct storage_info *info)
-{
-#ifndef HAVE_MULTIDRIVE
- const int drive=0;
-#endif
- info->sector_size=card_info[drive].blocksize;
- info->num_sectors=card_info[drive].numblocks;
- info->vendor="Rockbox";
- if(drive==0)
- {
- info->product="Internal Storage";
- }
- else
- {
- info->product="MMC Card Slot";
- }
- info->revision="0.00";
-}
-#endif
-
-#ifdef HAVE_HOTSWAP
-bool mmc_removable(IF_MD_NONVOID(int drive))
-{
-#ifndef HAVE_MULTIDRIVE
- const int drive=0;
-#endif
- return (drive==1);
-}
-
-bool mmc_present(IF_MD_NONVOID(int drive))
-{
-#ifndef HAVE_MULTIDRIVE
- const int drive=0;
-#endif
- if(drive==0)
- {
- return true;
- }
- else
- {
- return mmc_detect();
- }
-}
-#endif
-
-void mmc_spin(void)
-{
-}
-
-void mmc_spindown(int seconds)
-{
- (void)seconds;
-}
-
-#ifdef CONFIG_STORAGE_MULTI
-int mmc_num_drives(int first_drive)
-{
- mmc_first_drive = first_drive;
- return MMC_NUM_DRIVES;
-}
-#endif /* CONFIG_STORAGE_MULTI */
-
-int mmc_event(long id, intptr_t data)
-{
- return storage_event_default_handler(id, data, last_disk_activity,
- STORAGE_MMC);
-}