forked from len0rd/rockbox
Enhanced MMC handling: Driver cleanup, timeout calculation fixed, allowed voltage check, maintain disk activity info (fixes immediate shutdown at end of playback). MMC debug menu item populated.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5193 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
30c1358f87
commit
6f9a7eb2c7
3 changed files with 278 additions and 88 deletions
|
|
@ -54,6 +54,9 @@
|
|||
#ifdef CONFIG_TUNER
|
||||
#include "radio.h"
|
||||
#endif
|
||||
#ifdef HAVE_MMC
|
||||
#include "ata_mmc.h"
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/* SPECIAL DEBUG STUFF */
|
||||
|
|
@ -1260,9 +1263,134 @@ static bool view_runtime(void)
|
|||
}
|
||||
|
||||
#ifdef HAVE_MMC
|
||||
static bool dbg_mmc_info(void)
|
||||
/* value is 10 * real value */
|
||||
static unsigned char prep_value_unit(unsigned int *value,
|
||||
const unsigned char *units)
|
||||
{
|
||||
splash(HZ, true, "To be implemented.");
|
||||
int unit_no = 0;
|
||||
|
||||
while (*value >= 10000)
|
||||
{
|
||||
*value /= 1000;
|
||||
unit_no++;
|
||||
}
|
||||
return units[unit_no];
|
||||
}
|
||||
|
||||
bool dbg_mmc_info(void)
|
||||
{
|
||||
bool done = false;
|
||||
int currval = 0;
|
||||
unsigned int value;
|
||||
tCardInfo *card;
|
||||
unsigned char pbuf[32];
|
||||
unsigned char card_name[7];
|
||||
unsigned char unit;
|
||||
|
||||
static const unsigned char i_vmin[] = { 0, 1, 5, 10, 25, 35, 60, 100 };
|
||||
static const unsigned char i_vmax[] = { 1, 5, 10, 25, 35, 45, 80, 200 };
|
||||
|
||||
card_name[6] = '\0';
|
||||
|
||||
lcd_setmargins(0, 0);
|
||||
lcd_setfont(FONT_SYSFIXED);
|
||||
|
||||
while (!done)
|
||||
{
|
||||
card = mmc_card_info(currval / 2);
|
||||
|
||||
lcd_clear_display();
|
||||
snprintf(pbuf, sizeof(pbuf), "[MMC%d p%d]", currval / 2,
|
||||
(currval % 2) + 1);
|
||||
lcd_puts(0, 0, pbuf);
|
||||
|
||||
if (card->initialized)
|
||||
{
|
||||
if (!(currval % 2)) /* General info */
|
||||
{
|
||||
strncpy(card_name, ((unsigned char*)card->cid) + 3, 6);
|
||||
snprintf(pbuf, sizeof(pbuf), "%s Rev %d.%d", card_name,
|
||||
mmc_extract_bits(card->cid, 72, 4),
|
||||
mmc_extract_bits(card->cid, 76, 4));
|
||||
lcd_puts(0, 1, pbuf);
|
||||
snprintf(pbuf, sizeof(pbuf), "Prod: %d/%d",
|
||||
mmc_extract_bits(card->cid, 112, 4),
|
||||
mmc_extract_bits(card->cid, 116, 4) + 1997);
|
||||
lcd_puts(0, 2, pbuf);
|
||||
snprintf(pbuf, sizeof(pbuf), "Ser#: 0x%08x",
|
||||
mmc_extract_bits(card->cid, 80, 32));
|
||||
lcd_puts(0, 3, pbuf);
|
||||
snprintf(pbuf, sizeof(pbuf), "M=%02x, O=%04x",
|
||||
mmc_extract_bits(card->cid, 0, 8),
|
||||
mmc_extract_bits(card->cid, 8, 16));
|
||||
lcd_puts(0, 4, pbuf);
|
||||
value = mmc_extract_bits(card->csd, 54, 12)
|
||||
* (SECTOR_SIZE << (mmc_extract_bits(card->csd, 78, 3)+2));
|
||||
snprintf(pbuf, sizeof(pbuf), "Size: %d MB",
|
||||
value / (1024*1024));
|
||||
lcd_puts(0, 5, pbuf);
|
||||
}
|
||||
else /* Technical details */
|
||||
{
|
||||
value = card->speed / 100;
|
||||
unit = prep_value_unit(&value, "kMG");
|
||||
if (value < 100)
|
||||
snprintf(pbuf, sizeof(pbuf), "Speed: %d.%01d %cBit/s",
|
||||
value / 10, value % 10, unit);
|
||||
else
|
||||
snprintf(pbuf, sizeof(pbuf), "Tsac: %d %cBit/s",
|
||||
value / 10, unit);
|
||||
lcd_puts(0, 1, pbuf);
|
||||
|
||||
value = card->tsac;
|
||||
unit = prep_value_unit(&value, "nµm");
|
||||
if (value < 100)
|
||||
snprintf(pbuf, sizeof(pbuf), "Tsac: %d.%01d %cs",
|
||||
value / 10, value % 10, unit);
|
||||
else
|
||||
snprintf(pbuf, sizeof(pbuf), "Tsac: %d %cs",
|
||||
value / 10, unit);
|
||||
lcd_puts(0, 1, pbuf);
|
||||
|
||||
snprintf(pbuf, sizeof(pbuf), "Nsac: %d clk", card->nsac);
|
||||
lcd_puts(0, 2, pbuf);
|
||||
snprintf(pbuf, sizeof(pbuf), "R2W: *%d", card->r2w_factor);
|
||||
lcd_puts(0, 3, pbuf);
|
||||
snprintf(pbuf, sizeof(pbuf), "IRmax: %d..%d mA",
|
||||
i_vmin[mmc_extract_bits(card->csd, 66, 3)],
|
||||
i_vmax[mmc_extract_bits(card->csd, 69, 3)]);
|
||||
lcd_puts(0, 4, pbuf);
|
||||
snprintf(pbuf, sizeof(pbuf), "IWmax: %d..%d mA",
|
||||
i_vmin[mmc_extract_bits(card->csd, 72, 3)],
|
||||
i_vmax[mmc_extract_bits(card->csd, 75, 3)]);
|
||||
lcd_puts(0, 5, pbuf);
|
||||
}
|
||||
}
|
||||
else
|
||||
lcd_puts(0, 1, "Not found!");
|
||||
|
||||
lcd_update();
|
||||
|
||||
switch (button_get(true))
|
||||
{
|
||||
case SETTINGS_OK:
|
||||
case SETTINGS_CANCEL:
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case SETTINGS_DEC:
|
||||
currval--;
|
||||
if (currval < 0)
|
||||
currval = 3;
|
||||
break;
|
||||
|
||||
case SETTINGS_INC:
|
||||
currval++;
|
||||
if (currval > 3)
|
||||
currval = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
****************************************************************************/
|
||||
#include <stdbool.h>
|
||||
#include "ata.h"
|
||||
#include "ata_mmc.h"
|
||||
#include "kernel.h"
|
||||
#include "thread.h"
|
||||
#include "led.h"
|
||||
|
|
@ -106,22 +107,6 @@ static const unsigned char dummy[] = {
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool initialized;
|
||||
unsigned char bitrate_register;
|
||||
unsigned char rev;
|
||||
unsigned char rev_fract;
|
||||
unsigned int speed; /* bps */
|
||||
unsigned int read_timeout; /* n * 8 clock cycles */
|
||||
unsigned int write_timeout; /* n * 8 clock cycles */
|
||||
unsigned int size; /* in bytes */
|
||||
unsigned int manuf_month;
|
||||
unsigned int manuf_year;
|
||||
unsigned long serial_number;
|
||||
unsigned char name[7];
|
||||
} tCardInfo;
|
||||
|
||||
static tCardInfo card_info[2];
|
||||
|
||||
/* private function declarations */
|
||||
|
|
@ -150,6 +135,8 @@ static int select_card(int card_no)
|
|||
else /* external */
|
||||
and_b(~0x10, &PADRH); /* clear clock gate PA12 CHECKME: mask?*/
|
||||
|
||||
last_disk_activity = current_tick;
|
||||
|
||||
if (!card_info[card_no].initialized)
|
||||
{
|
||||
setup_sci1(7); /* Initial rate: 375 kbps (need <= 400 per mmc specs) */
|
||||
|
|
@ -177,6 +164,8 @@ static void deselect_card(void)
|
|||
{
|
||||
while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
|
||||
or_b(0x06, &PADRH); /* deassert CS (both cards) */
|
||||
|
||||
last_disk_activity = current_tick;
|
||||
}
|
||||
|
||||
static void setup_sci1(int bitrate_register)
|
||||
|
|
@ -235,8 +224,7 @@ static void read_transfer(unsigned char *buf, int len)
|
|||
*buf = fliptable[(signed char)(RDR1)]; /* read & bitswap */
|
||||
}
|
||||
|
||||
/* timeout is in bytes */
|
||||
static unsigned char poll_byte(int timeout)
|
||||
static unsigned char poll_byte(int timeout) /* timeout is in bytes */
|
||||
{
|
||||
int i;
|
||||
unsigned char data = 0; /* stop the compiler complaining */
|
||||
|
|
@ -254,7 +242,7 @@ static unsigned char poll_byte(int timeout)
|
|||
return fliptable[(signed char)data];
|
||||
}
|
||||
|
||||
static unsigned char poll_busy(int timeout)
|
||||
static unsigned char poll_busy(int timeout) /* timeout is in bytes */
|
||||
{
|
||||
int i;
|
||||
unsigned char data, dummy;
|
||||
|
|
@ -362,101 +350,134 @@ static int send_data(char start_token, const unsigned char *buf, int len,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static int initialize_card(int card_no)
|
||||
{
|
||||
int i, temp;
|
||||
unsigned char response;
|
||||
unsigned char cxd[16];
|
||||
unsigned char response[5];
|
||||
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 speed_exponent[] = { /* /10 */
|
||||
10000, 100000, 1000000, 10000000, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static const int time_exponent[] = { /* reciprocal */
|
||||
1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100
|
||||
static const int exponent[] = { /* use varies */
|
||||
1, 10, 100, 1000, 10000, 100000, 1000000,
|
||||
10000000, 100000000, 1000000000
|
||||
};
|
||||
|
||||
/* switch to SPI mode */
|
||||
send_cmd(CMD_GO_IDLE_STATE, 0, &response);
|
||||
if (response != 0x01)
|
||||
send_cmd(CMD_GO_IDLE_STATE, 0, response);
|
||||
if (response[0] != 0x01)
|
||||
return -1; /* error response */
|
||||
|
||||
/* initialize card */
|
||||
i = 0;
|
||||
while (send_cmd(CMD_SEND_OP_COND, 0, &response) && (++i < 200));
|
||||
if (response != 0x00)
|
||||
while (send_cmd(CMD_SEND_OP_COND, 0, response) && (++i < 200));
|
||||
if (response[0] != 0x00)
|
||||
return -2; /* not ready */
|
||||
|
||||
/* get CSD register */
|
||||
if (send_cmd(CMD_SEND_CSD, 0, &response))
|
||||
/* get OCR register */
|
||||
if (send_cmd(CMD_READ_OCR, 0, response))
|
||||
return -3;
|
||||
if (receive_data(cxd, 16, 50))
|
||||
card->ocr = (response[1] << 24) + (response[2] << 16)
|
||||
+ (response[3] << 8) + response[4];
|
||||
|
||||
/* check voltage */
|
||||
if (!(card->ocr & 0x00100000)) /* 3.2 .. 3.3 V */
|
||||
return -4;
|
||||
|
||||
/* check block size */
|
||||
if (1 << (cxd[5] & 0x0F) != SECTOR_SIZE)
|
||||
/* get CSD register */
|
||||
if (send_cmd(CMD_SEND_CSD, 0, response))
|
||||
return -5;
|
||||
if (receive_data((unsigned char*)card->csd, 16, 20))
|
||||
return -6;
|
||||
|
||||
/* max transmission speed the card is capable of */
|
||||
card->speed = mantissa[(cxd[3] & 0x78) >> 3]
|
||||
* speed_exponent[(cxd[3] & 0x07)];
|
||||
/* check block size */
|
||||
if ((1 << mmc_extract_bits(card->csd, 44, 4)) != SECTOR_SIZE)
|
||||
return -7;
|
||||
|
||||
/* calculate the clock divider */
|
||||
/* 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];
|
||||
card->bitrate_register = (FREQ/4-1) / card->speed;
|
||||
|
||||
/* calculate read timeout in clock cycles from TSAC, NSAC and the actual
|
||||
* clock frequency */
|
||||
temp = (FREQ/4) / (card->bitrate_register + 1); /* actual frequency */
|
||||
card->read_timeout =
|
||||
(temp * mantissa[(cxd[1] & 0x78) >> 3] + (1000 * cxd[2]))
|
||||
/ (time_exponent[cxd[1] & 0x07] * 8);
|
||||
/* 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];
|
||||
|
||||
/* calculate write timeout */
|
||||
temp = (cxd[12] & 0x1C) >> 2;
|
||||
if (temp > 5)
|
||||
temp = 5;
|
||||
card->write_timeout = card->read_timeout * (1 << temp);
|
||||
|
||||
/* calculate size */
|
||||
card->size = ((unsigned int)(cxd[6] & 0x03) << 10)
|
||||
+ ((unsigned int)cxd[7] << 2)
|
||||
+ ((unsigned int)(cxd[8] & 0xC0) >> 6);
|
||||
temp = ((cxd[9] & 0x03) << 1) + ((cxd[10] & 0x80) >> 7) + 2;
|
||||
card->size *= (SECTOR_SIZE << 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;
|
||||
|
||||
/* switch to full speed */
|
||||
setup_sci1(card->bitrate_register);
|
||||
|
||||
/* get CID register */
|
||||
if (send_cmd(CMD_SEND_CID, 0, &response))
|
||||
return -6;
|
||||
if (receive_data(cxd, 16, 50))
|
||||
return -7;
|
||||
|
||||
/* get data from CID */
|
||||
strncpy(card->name, &cxd[3], 6);
|
||||
card->name[6] = '\0';
|
||||
|
||||
card->rev = (cxd[9] & 0xF0) >> 4;
|
||||
card->rev_fract = cxd[9] & 0x0F;
|
||||
|
||||
card->manuf_month = (cxd[14] & 0xF0) >> 4;
|
||||
card->manuf_year = (cxd[14] & 0x0F) + 1997;
|
||||
|
||||
card->serial_number = ((unsigned long)cxd[10] << 24)
|
||||
+ ((unsigned long)cxd[11] << 16)
|
||||
+ ((unsigned long)cxd[12] << 8)
|
||||
+ (unsigned long)cxd[13];
|
||||
if (send_cmd(CMD_SEND_CID, 0, response))
|
||||
return -8;
|
||||
if (receive_data((unsigned char*)card->cid, 16, 20))
|
||||
return -9;
|
||||
|
||||
card->initialized = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tCardInfo *mmc_card_info(int card_no)
|
||||
{
|
||||
tCardInfo *card = &card_info[card_no];
|
||||
|
||||
if (!card->initialized)
|
||||
{
|
||||
select_card(card_no);
|
||||
deselect_card();
|
||||
}
|
||||
return card;
|
||||
}
|
||||
|
||||
int ata_read_sectors(unsigned long start,
|
||||
int incount,
|
||||
void* inbuf)
|
||||
|
|
@ -467,9 +488,6 @@ int ata_read_sectors(unsigned long start,
|
|||
unsigned char response;
|
||||
tCardInfo *card = &card_info[current_card];
|
||||
|
||||
if (incount <= 0)
|
||||
return ret;
|
||||
|
||||
addr = start * SECTOR_SIZE;
|
||||
|
||||
mutex_lock(&mmc_mutex);
|
||||
|
|
@ -482,6 +500,7 @@ int ata_read_sectors(unsigned long start,
|
|||
ret = send_cmd(CMD_READ_SINGLE_BLOCK, addr, &response);
|
||||
if (ret == 0)
|
||||
ret = receive_data(inbuf, SECTOR_SIZE, card->read_timeout);
|
||||
last_disk_activity = current_tick;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -490,6 +509,7 @@ int ata_read_sectors(unsigned long start,
|
|||
{
|
||||
ret = receive_data(inbuf, SECTOR_SIZE, card->read_timeout);
|
||||
inbuf += SECTOR_SIZE;
|
||||
last_disk_activity = current_tick;
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = send_cmd(CMD_STOP_TRANSMISSION, 0, &response);
|
||||
|
|
@ -519,9 +539,6 @@ int ata_write_sectors(unsigned long start,
|
|||
if (start == 0)
|
||||
panicf("Writing on sector 0\n");
|
||||
|
||||
if (count <= 0)
|
||||
return ret;
|
||||
|
||||
addr = start * SECTOR_SIZE;
|
||||
|
||||
mutex_lock(&mmc_mutex);
|
||||
|
|
@ -535,6 +552,7 @@ int ata_write_sectors(unsigned long start,
|
|||
if (ret == 0)
|
||||
ret = send_data(DT_START_BLOCK, buf, SECTOR_SIZE,
|
||||
card->write_timeout);
|
||||
last_disk_activity = current_tick;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -544,12 +562,14 @@ int ata_write_sectors(unsigned long start,
|
|||
ret = send_data(DT_START_WRITE_MULTIPLE, buf, SECTOR_SIZE,
|
||||
card->write_timeout);
|
||||
buf += SECTOR_SIZE;
|
||||
last_disk_activity = current_tick;
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
response = DT_STOP_TRAN;
|
||||
write_transfer(&response, 1);
|
||||
poll_busy(card->write_timeout);
|
||||
last_disk_activity = current_tick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
42
firmware/export/ata_mmc.h
Normal file
42
firmware/export/ata_mmc.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2004 by Jens Arnold
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __ATA_MMC_H__
|
||||
#define __ATA_MMC_H__
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool initialized;
|
||||
unsigned char bitrate_register;
|
||||
unsigned int read_timeout; /* n * 8 clock cycles */
|
||||
unsigned int write_timeout; /* n * 8 clock cycles */
|
||||
|
||||
unsigned long ocr; /* OCR register */
|
||||
unsigned long csd[4]; /* CSD register, 16 bytes */
|
||||
unsigned long cid[4]; /* CID register, 16 bytes */
|
||||
unsigned int speed; /* bit/s */
|
||||
unsigned int nsac; /* clock cycles */
|
||||
unsigned int tsac; /* n * 0.1 ns */
|
||||
unsigned int r2w_factor;
|
||||
} tCardInfo;
|
||||
|
||||
unsigned long mmc_extract_bits(const unsigned long *p, unsigned int start,
|
||||
unsigned int size);
|
||||
tCardInfo *mmc_card_info(int card_no);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue