diff options
Diffstat (limited to 'firmware/target/sh/archos/ondio/ata_mmc.c')
-rw-r--r-- | firmware/target/sh/archos/ondio/ata_mmc.c | 978 |
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); -} |