1
0
Fork 0
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:
Jens Arnold 2004-10-06 20:43:12 +00:00
parent 30c1358f87
commit 6f9a7eb2c7
3 changed files with 278 additions and 88 deletions

View file

@ -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;
}

View file

@ -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
View 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