summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2004-10-06 20:43:12 +0000
committerJens Arnold <amiconn@rockbox.org>2004-10-06 20:43:12 +0000
commit6f9a7eb2c7d6f81e54b47c917be79f5126ba8982 (patch)
tree22dc11305494ed12060699821641813f6246b84a
parent30c1358f87c68d5bc78178bb3af9e8e3b8c660e6 (diff)
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
-rw-r--r--apps/debug_menu.c132
-rw-r--r--firmware/drivers/ata_mmc.c194
-rw-r--r--firmware/export/ata_mmc.h42
3 files changed, 279 insertions, 89 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index cb6ad07c4a..663ea7bdf4 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -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)
+{
+ int unit_no = 0;
+
+ while (*value >= 10000)
+ {
+ *value /= 1000;
+ unit_no++;
+ }
+ return units[unit_no];
+}
+
+bool dbg_mmc_info(void)
{
- splash(HZ, true, "To be implemented.");
+ 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;
}
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c
index 7a187f092b..ea7c5f1737 100644
--- a/firmware/drivers/ata_mmc.c
+++ b/firmware/drivers/ata_mmc.c
@@ -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 */
@@ -149,6 +134,8 @@ static int select_card(int card_no)
or_b(0x10, &PADRH); /* set clock gate PA12 CHECKME: mask? */
else /* external */
and_b(~0x10, &PADRH); /* clear clock gate PA12 CHECKME: mask?*/
+
+ last_disk_activity = current_tick;
if (!card_info[card_no].initialized)
{
@@ -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))
- return -4;
+ card->ocr = (response[1] << 24) + (response[2] << 16)
+ + (response[3] << 8) + response[4];
- /* check block size */
- if (1 << (cxd[5] & 0x0F) != SECTOR_SIZE)
+ /* check voltage */
+ if (!(card->ocr & 0x00100000)) /* 3.2 .. 3.3 V */
+ return -4;
+
+ /* 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)];
-
- /* calculate the clock divider */
+ /* 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];
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);
-
- /* 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);
+ /* 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;
/* 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;
}
}
}
diff --git a/firmware/export/ata_mmc.h b/firmware/export/ata_mmc.h
new file mode 100644
index 0000000000..afc0dc24af
--- /dev/null
+++ b/firmware/export/ata_mmc.h
@@ -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