dslinux/linux-2.6.x/drivers/mmc scsd_c.c scsd_s.S
amadeus
dslinux_amadeus at user.in-berlin.de
Sun Aug 27 18:31:29 CEST 2006
Update of /cvsroot/dslinux/dslinux/linux-2.6.x/drivers/mmc
In directory antilope:/tmp/cvs-serv9224/linux-2.6.x/drivers/mmc
Modified Files:
scsd_c.c scsd_s.S
Log Message:
Rewrite of SD driver to allow 32 MByte GBA ROM space used as RAM
Index: scsd_c.c
===================================================================
RCS file: /cvsroot/dslinux/dslinux/linux-2.6.x/drivers/mmc/scsd_c.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- scsd_c.c 15 Aug 2006 08:27:14 -0000 1.4
+++ scsd_c.c 27 Aug 2006 16:31:27 -0000 1.5
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/scsd_c.c - Supercard SD driver
+ * linux/drivers/mmc/scsd_c.c - Nintendo DS SD driver
*
* Copyright (C) 2006 Amadeus, All Rights Reserved.
* Based on the old non-mmc driver by by Jean-Pierre Thomasset.
@@ -7,9 +7,6 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * This driver must be in Main Memory or in the first 16 MBytes of GBA Slot ROM.
- * The 2nd 16 MBytes of Slot ROM are switched to IO mode.
*/
#include <linux/config.h>
#include <linux/module.h>
@@ -23,6 +20,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/protocol.h>
#include <linux/kmod.h>
+#include <linux/timer.h>
#include <asm/dma.h>
#include <asm/io.h>
@@ -30,8 +28,8 @@
#include <asm/scatterlist.h>
#include <asm/sizes.h>
-#undef READ_CRC /* do CRC for data reads */
-#undef HALT_ON_ERROR /* stop after error, so we can see what's happened */
+#undef READ_CRC /* do CRC for data reads */
+#undef HALT_ON_ERROR /* stop after error, so we can see what's happened */
#ifdef CONFIG_MMC_DEBUG
#define READ_CRC
@@ -47,24 +45,10 @@
#define halt() do { } while (0)
#endif
-#define DRIVER_NAME "scsd"
-#define DRIVER_VERSION "1.0.1"
-
-/*****************************************************************************/
-/* IO registers */
-#define SC_SD_CMD 0x09800000
- /* bit 0: data bit to read */
- /* bit 7: data bit to write */
-
-#define SC_SD_DATAWRITE 0x09000000
-#define SC_SD_DATAREAD 0x09100000
-#define SC_SDL_DOWRITE 0x09440000
- /* SC lite: write 0 before write command */
+#define BLOCKSIZE 512
-#define SC_SD_LOCK 0x09FFFFFE
- /* bit 0: 1 */
- /* bit 1: enable IO interface (SD,CF) */
- /* bit 2: enable R/W SDRAM access */
+#define DRIVER_NAME "scsd"
+#define DRIVER_VERSION "1.1.2"
/*****************************************************************************/
@@ -74,22 +58,88 @@
};
/*****************************************************************************/
-/* Assembler functions in scsd_s.S */
-extern void sd_crc16_s(u16* buff, u16 num, u16* crc16buff);
-extern void sd_data_write_s(u16 *buff, u32 length);
-extern void sd_data_read_s(u16 *buff, u32 length);
+/* Structure for device-specific functions in assembler.
+*/
+struct sd_functions {
+ /* Test if the card is present.
+ Return != 0 if present. */
+ int (*detect_card) (void);
+
+ /* Say if the data transfer is 1 or 4 bit.
+ Return != 0 if 4 bit. */
+ int (*transfer_nibbles) (void);
+
+ /* Write at minimum 8 clock cycles to the card.
+ Wait max. 1ms for the CMD line to become HIGH.
+ Send a command to the card. Skip 2 Z bits.
+ data = pointer to start of command. 32bit aligned.
+ len = length of the command (including CRC7).
+ Return != 0 if OK, 0 if timeout. */
+ int (*send_command) (u8 *data, int len);
+
+ /* Wait max. 1ms for the CMD line to become LOW.
+ Read a response from the device and skip 2 Z bits.
+ data = pointer to start of response buffer. 32bit aligned.
+ len = number of bytes to read(including CRC).
+ Return != 0 if OK, 0 if timeout. */
+ int (*read_response) (u8* data, int len);
+
+ /* Wait for the DATA line to become HIGH.
+ Return != 0 if OK, 0 if timeout.
+ Maximum length of testing is 1ms. */
+ int (*wait_ready) (void);
+
+ /* Write a start bit, send a Data block incl. CRC.
+ Write the end bit. Skip 2 Z bits.
+ Wait max. 1ms for the start of the CRC response.
+ Check the CRC response.
+ data = pointer to start of data. 32bit aligned.
+ len = number of bytes to send.
+ Return != 0 if OK, 0 if CRC missing or error. */
+ int (*send_data) (u8 *data, int len);
+
+ /* Wait max 1ms for the DATA line to become LOW.
+ Receive a Data block and CRC, skip the end bit.
+ data = pointer to start of data. 32bit aligned.
+ len = number of bytes to receive (incl. CRC)
+ Return != 0 if OK, 0 if timeout. */
+ int (*read_data) (u8 *data, int len);
+
+ /* Read the write protect switch.
+ Return != 0 if readonly, 0 if r/w.
+ When in doubt, return 0. */
+ int (*read_only) (void);
+
+ /* Write at minimum 8 clock cycles to the card. */
+ void (*send_clocks) (void);
+};
/*****************************************************************************/
+/* Active link to device-specific functions.
+*/
+static struct sd_functions *sd_dev;
-/* Unlock the SD interface. */
-inline static void scsd_unlock( void )
-{
- writew(0xa55a, SC_SD_LOCK);
- writew(0xa55a, SC_SD_LOCK);
- /* we switch GBA ROM to r/w here */
- writew(0x0007, SC_SD_LOCK);
- writew(0x0007, SC_SD_LOCK);
-}
+/*****************************************************************************/
+/* Timer delayed execution of last clocks */
+static volatile int sd_active;
+static struct timer_list clock_timer;
+
+/*****************************************************************************/
+/* Buffer in main memory(!), for transfer of commands, responses and data
+ between the C and assembler part of this driver. This buffer is 32bit aligned.
+ This buffer holds data and CRC (two times for reading).
+*/
+static u8 sd_databuf[BLOCKSIZE+16] __attribute__ ((aligned (4)));
+
+/*****************************************************************************/
+/* Device-specific functions.
+*/
+#ifdef CONFIG_MMC_SCSD
+/* Supercard SD(mini,lite) */
+extern struct sd_functions supercard_functions;
+#endif
+
+/*****************************************************************************/
/* Improved CRC7 function provided by cory1492 */
inline static u8 scsd_crc7(u8* data, int cnt)
@@ -112,94 +162,109 @@
return(crc);
}
-/* write a single byte of a SD command */
-inline static void scsd_write_command_byte(u32 data)
+/* Calculate the data crc.
+ data = pointer to start of data. 32bit aligned.
+ len = number of bytes of CRC calculation.
+ crc = pointer to start of CRC.
+*/
+/* non-static */ void scsd_calc_crc(u8 *data, int len, u8* crc)
{
- /* With every 16 bit write to SC_SD_CMD, write a single bit. */
- /* We are writing 32 bit == 2 bits of the command per cycle. */
- /* The bit to write is in D7 of SC_SD_CMD. */
- u32 ioadr = SC_SD_CMD;
- data |= data << 17;
- writel(data, ioadr);
- data <<= 2;
- writel(data, ioadr);
- data <<= 2;
- writel(data, ioadr);
- data <<= 2;
- writel(data, ioadr);
+ __asm__ __volatile__(
+" mov r9,%2 \n"
+" \n"
+" mov r3,#0 \n"
+" mov r4,#0 \n"
+" mov r5,#0 \n"
+" mov r6,#0 \n"
+" \n"
+" ldr r7,=0x80808080 \n"
+" ldr r8,=0x1021 \n"
+" mov %1,%1,lsl #3 \n"
+"1: \n"
+" tst r7,#0x80 \n"
+" ldrneb %2,[%0],#1 \n"
+" \n"
+" mov r3,r3,lsl #1 \n"
+" tst r3,#0x10000 \n"
+" eorne r3,r3,r8 \n"
+" tst %2,r7,lsr #24 \n"
+" eorne r3,r3,r8 \n"
+" \n"
+" mov r4,r4,lsl #1 \n"
+" tst r4,#0x10000 \n"
+" eorne r4,r4,r8 \n"
+" tst %2,r7,lsr #25 \n"
+" eorne r4,r4,r8 \n"
+" \n"
+" mov r5,r5,lsl #1 \n"
+" tst r5,#0x10000 \n"
+" eorne r5,r5,r8 \n"
+" tst %2,r7,lsr #26 \n"
+" eorne r5,r5,r8 \n"
+" \n"
+" mov r6,r6,lsl #1 \n"
+" tst r6,#0x10000 \n"
+" eorne r6,r6,r8 \n"
+" tst %2,r7,lsr #27 \n"
+" eorne r6,r6,r8 \n"
+" \n"
+" mov r7,r7,ror #4 \n"
+" subs %1,%1,#4 \n"
+" bne 1b \n"
+" \n"
+" mov %2,r9 \n"
+" mov r8,#16 \n"
+"2: \n"
+" mov r7,r7,lsl #4 \n"
+" tst r3,#0x8000 \n"
+" orrne r7,r7,#8 \n"
+" tst r4,#0x8000 \n"
+" orrne r7,r7,#4 \n"
+" tst r5,#0x8000 \n"
+" orrne r7,r7,#2 \n"
+" tst r6,#0x8000 \n"
+" orrne r7,r7,#1 \n"
+" \n"
+" mov r3,r3,lsl #1 \n"
+" mov r4,r4,lsl #1 \n"
+" mov r5,r5,lsl #1 \n"
+" mov r6,r6,lsl #1 \n"
+" \n"
+" sub r8,r8,#1 \n"
+" tst r8,#1 \n"
+" streqb r7,[%2],#1 \n"
+" cmp r8,#0 \n"
+" bne 2b \n"
+" \n"
+ : /* no output registers */
+ : "r" (data), "r" (len), "r" (crc)
+ : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "cc");
}
-/* read a single byte of a SD response */
-static u32 scsd_read_response_byte(void)
-{
- /* With every 16 bit read to SC_SD_CMD, read a single bit. */
- /* So we read 32 bits and get 2 data bits. */
- u32 ioadr = SC_SD_CMD;
- u32 temp;
- u32 res = 0;
- temp = readl(ioadr);
- if (temp & 0x00000001)
- res |= 0x80;
- if (temp & 0x00010000)
- res |= 0x40;
- temp = readl(ioadr);
- if (temp & 0x00000001)
- res |= 0x20;
- if (temp & 0x00010000)
- res |= 0x10;
- temp = readl(ioadr);
- if (temp & 0x00000001)
- res |= 0x08;
- if (temp & 0x00010000)
- res |= 0x04;
- temp = readl(ioadr);
- if (temp & 0x00000001)
- res |= 0x02;
- if (temp & 0x00010000)
- res |= 0x01;
- return res;
-}
/* Wait until ready on the data lines */
/* return 0 if ready, 1 if busy */
-static int scsd_waitready(void)
+inline static int scsd_waitready(void)
{
- u32 ioadr = SC_SD_DATAREAD;
- u32 tries = 2000000; /* app. 1000 ms */
- u32 count = 0;
-
- /* skip max. 2 Z-bits */
- readl(ioadr);
+ int i;
- do {
- if (readw(ioadr) & 0x0100) {
- /* data line is high */
- count++;
- if (count > 8) {
- /* minimum 8 bit not busy */
- return 0;
- }
- } else {
- /* data line is low */
- count = 0;
- tries--;
- if (!tries) {
- /* busy for a very long time */
- return 1;
- }
- }
- } while (1);
+ for (i = 1000; i; i--) {
+ if (sd_dev->wait_ready())
+ return 0;
+ }
+ return 1;
}
/* send a SD command */
/* @return 0 for success, != 0 otherwise */
static int scsd_send_cmd(struct mmc_command *cmd)
{
- u8 databuff[6];
- u8 *p = &databuff[0];
- u32 ioadr = SC_SD_CMD;
+ u8 *p = sd_databuf;
int i;
+ /* stop the clock timer, we will send a command */
+ del_timer(&clock_timer);
+
/* Start without error */
cmd->error = MMC_ERR_NONE;
@@ -209,27 +274,20 @@
*p++ = cmd->arg >> 16;
*p++ = cmd->arg >> 8;
*p++ = cmd->arg;
- *p = scsd_crc7(databuff, 5);
+ *p = scsd_crc7(sd_databuf, 5);
- /* wait for CMD line high */
- i = 500000; /* app. 250 ms */
- while (!(readw(ioadr) & 0x0001) && i) i--;
+ /* waiting for CMD line high, write command to card */
+ for (i = 250; i; i--) {
+ if (sd_dev->send_command(sd_databuf, 6))
+ break;
+ }
if (!i) {
- printk( KERN_ERR "CMD:timeout after command\n");
+ printk( KERN_ERR "CMD:Timeout before command\n");
cmd->error = MMC_ERR_TIMEOUT;
halt();
return -1;
}
- /* one extra wait clk needed here ... */
- readw(ioadr);
-
- // output command
- p = &databuff[0];
- for (i = 6; i; i--) {
- scsd_write_command_byte(*p++);
- }
-
/* what type of response do we get? */
switch (cmd->flags & MMC_RSP_MASK) {
@@ -239,9 +297,6 @@
case MMC_RSP_SHORT: /* 48 bit = 6 bytes response */
case MMC_RSP_LONG: /* 136 bit response */
- // skip two Z bits
- readl(ioadr);
-
/* Skip response, if it is a read data command.
Response and data may come the same time. */
switch (cmd->opcode) {
@@ -252,41 +307,37 @@
return 0;
}
- /* Wait for start bit of response */
- i = 100; /* Ncr == 64 */
- while ((readw(ioadr) & 0x0001) && i) i--;
- if (!i) {
+ /* Read the response */
+ if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_LONG)
+ i = 18;
+ else
+ i = 6;
+ if (!sd_dev->read_response(sd_databuf, i)) {
/* Timeout error */
- printk(KERN_ERR "Timeout after Command\n");
+ printk(KERN_ERR "CMD:Timeout after command\n");
cmd->error = MMC_ERR_TIMEOUT;
return -1;
}
-
- /* Skip rest of first byte (the command) */
- i=7; while (i--) readw(ioadr);
-
- /* get response */
- cmd->resp[0] = scsd_read_response_byte() << 24;
- cmd->resp[0] |= scsd_read_response_byte() << 16;
- cmd->resp[0] |= scsd_read_response_byte() << 8;
- cmd->resp[0] |= scsd_read_response_byte();
+ p = sd_databuf;
+ p++; /* skip command byte */
+ cmd->resp[0] = *p++ << 24;
+ cmd->resp[0] |= *p++ << 16;
+ cmd->resp[0] |= *p++ << 8;
+ cmd->resp[0] |= *p++;
if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_LONG) {
- cmd->resp[1] = scsd_read_response_byte() << 24;
- cmd->resp[1] |= scsd_read_response_byte() << 16;
- cmd->resp[1] |= scsd_read_response_byte() << 8;
- cmd->resp[1] |= scsd_read_response_byte();
- cmd->resp[2] = scsd_read_response_byte() << 24;
- cmd->resp[2] |= scsd_read_response_byte() << 16;
- cmd->resp[2] |= scsd_read_response_byte() << 8;
- cmd->resp[2] |= scsd_read_response_byte();
- cmd->resp[3] = scsd_read_response_byte() << 24;
- cmd->resp[3] |= scsd_read_response_byte() << 16;
- cmd->resp[3] |= scsd_read_response_byte() << 8;
- cmd->resp[3] |= scsd_read_response_byte();
+ cmd->resp[1] = *p++ << 24;
+ cmd->resp[1] |= *p++ << 16;
+ cmd->resp[1] |= *p++ << 8;
+ cmd->resp[1] |= *p++;
+ cmd->resp[2] = *p++ << 24;
+ cmd->resp[2] |= *p++ << 16;
+ cmd->resp[2] |= *p++ << 8;
+ cmd->resp[2] |= *p++;
+ cmd->resp[3] = *p++ << 24;
+ cmd->resp[3] |= *p++ << 16;
+ cmd->resp[3] |= *p++ << 8;
+ cmd->resp[3] |= *p++;
}
- /* Skip CRC and 2 Z bits */
- i=5; while (i--) readl(ioadr);
-
DBG("Got native response %X %X %X %X\n", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
break;
default:
@@ -323,9 +374,6 @@
int size = data->blocks << data->blksz_bits;
struct scatterlist *sg = data->sg;
int i;
- u32 ioadr;
- u32 tmp;
- u16 crc16[4];
DBG("%s Bytes=%d\n",__FUNCTION__, size);
@@ -333,7 +381,7 @@
data->bytes_xfered = 0;
data->error = MMC_ERR_NONE;
for (sgindex = 0; sgindex < data->sg_len; sgindex++) {
- u16 *p;
+ u8 *p;
int sglength;
/* get the start address */
@@ -353,13 +401,12 @@
/* do the transfer */
if (data->flags & MMC_DATA_READ) {
- u16 crcread[4];
-
- ioadr = SC_SD_DATAREAD;
- /* test for data */
- i = 200000; /* app. 100 ms */
- while ((readw(ioadr) & 0x0100) && i) i--;
+ /* wait max. 100ms for start bit, read the data+crc+end bit */
+ for( i=100; i; i--) {
+ if (sd_dev->read_data(sd_databuf, length+8))
+ break;
+ }
if (!i) {
/* Timeout error */
printk(KERN_ERR "Read: timeout waiting for read data\n");
@@ -367,24 +414,11 @@
halt();
return;
}
-
- /* read the data */
- sd_data_read_s(p, length);
-
- /* read the CRC */
- sd_data_read_s(crcread, 8);
-
- /* read the end bit */
- readw(ioadr);
#ifdef READ_CRC
/* check the CRC */
- sd_crc16_s(p, length, crc16);
-#endif
- /* advance data pointer */
- p += (length/2);
-#ifdef READ_CRC
- for (i = 0; i < 4; i++) {
- if (crc16[i] != crcread[i]) {
+ scsd_calc_crc(sd_databuf, length, &sd_databuf[BLOCKSIZE+8]);
+ for (i = 0; i < 8; i++) {
+ if (sd_databuf[length+i] != sd_databuf[BLOCKSIZE+8+i]) {
printk (KERN_ERR "Read: CRC read different\n");
data->error = MMC_ERR_BADCRC;
halt();
@@ -392,80 +426,38 @@
}
}
#endif
+ /* copy the data */
+ memcpy(p, sd_databuf, length);
+
} else if (data->flags & MMC_DATA_WRITE) {
- /* Wait until ready on the data lines */
- if (scsd_waitready()) {
- /* Timeout error */
- printk(KERN_ERR "before Write: timeout waiting for ready\n");
- data->error = MMC_ERR_TIMEOUT;
- halt();
- return;
- }
- ioadr = SC_SD_DATAWRITE;
+ /* copy the data */
+ memcpy(sd_databuf, p, length);
/* calculate the crc */
- sd_crc16_s(p, length, crc16);
-
- /* write the start bit */
- writew(0, ioadr);
-
- /* write the data */
- sd_data_write_s(p, length);
-
- /* write the crc */
- sd_data_write_s(crc16, 8);
-
- /* write the end bit */
- writew(0xFF, ioadr);
-
- ioadr = SC_SD_DATAREAD;
-
- /* skip two Z bits */
- readl(ioadr);
+ scsd_calc_crc(sd_databuf, length, &sd_databuf[length]);
- i = 500000; /* app. 250 ms */
- while ((readw(ioadr) & 0x0100) && i) i--;
- if (!i) {
+ /* Wait until ready on the data lines */
+ if (scsd_waitready()) {
/* Timeout error */
- printk(KERN_ERR "Timeout waiting for CRC response\n");
+ printk(KERN_ERR "before Write: timeout waiting for ready\n");
data->error = MMC_ERR_TIMEOUT;
halt();
return;
}
- /* read CRC response (3 bit) + end bit */
- readl(ioadr);
- tmp = readl(ioadr);
- tmp >>= 16;
- /* CRC response is in bit 12,8,4 here */
- i = 0;
- if (tmp & 0x1000) i |= 0x04;
- if (tmp & 0x0100) i |= 0x02;
- if (tmp & 0x0010) i |= 0x01;
- DBG("CRC Response = %d\n", i);
- /* found that SD cards give response codes 2 AND 3, without error */
- if ((i != 2) && (i != 3)) {
- printk(KERN_ERR "Write: CRC bad code= %d tmp= %X\n", i, tmp);
- data->error = MMC_ERR_BADCRC;
- halt();
- return;
- }
-
- /* Wait until ready on the data lines */
- if (scsd_waitready()) {
+ /* Write data, check CRC response */
+ if (!sd_dev->send_data(sd_databuf, length+8)) {
/* Timeout error */
- printk(KERN_ERR "Write: timeout waiting for ready\n");
+ printk(KERN_ERR "BAD CRC response\n");
data->error = MMC_ERR_TIMEOUT;
halt();
return;
}
-
- /* advance data pointer */
- p += (length/2);
}
/* ready with one physical sector */
+ p += length;
data->bytes_xfered += length;
size -= length;
sglength -= length;
@@ -475,22 +467,33 @@
if (size <= 0) break;
}
+ if (data->flags & MMC_DATA_WRITE) {
+ /* Wait until ready on the data lines */
+ if (scsd_waitready()) {
+ /* Timeout error */
+ printk(KERN_ERR "Write: timeout waiting for ready\n");
+ data->error = MMC_ERR_TIMEOUT;
+ halt();
+ return;
+ }
+ }
DBG("xfer done\n");
}
static void scsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct scsd_host *host = mmc_priv(mmc);
-
- u32 ioadr = SC_SD_CMD;
int ret;
int retry = 1;
+ /* access to SD in progress */
+ sd_active = 1;
+
DBG("%s Opcode %d, arg %d\n",__FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg);
/* Fooling mmc core to only do 4bit data transfers.
- We don't have a function for doing 1bit data transfers. */
- if (mmc->card_selected) {
+ if the hardware/the driver can only do 4bit transfers. */
+ if (sd_dev->transfer_nibbles() && mmc->card_selected) {
mmc->card_selected->scr.bus_widths |= SD_SCR_BUS_WIDTH_4;
}
@@ -498,12 +501,8 @@
/* do a retry for data I/O */
case MMC_READ_SINGLE_BLOCK:
case MMC_READ_MULTIPLE_BLOCK:
- retry = 3;
- break;
case MMC_WRITE_BLOCK:
case MMC_WRITE_MULTIPLE_BLOCK:
- /* for SClite, switch to write mode */
- writew(0, SC_SDL_DOWRITE);
retry = 3;
break;
/* check if we have an inactivation command */
@@ -518,6 +517,7 @@
DBG("Fake Timeout for second SEND_CID\n");
mrq->cmd->error = MMC_ERR_TIMEOUT;
mmc_request_done(mmc, mrq);
+ sd_active = 0;
return;
}
break;
@@ -549,18 +549,30 @@
break;
}
- /* minimum 8 bits after last command */
- ret=4; while (ret--) readl(ioadr);
+ /* access done */
+ sd_active = 0;
- mmc_request_done(mmc, mrq);
+ /* start timer for the last clock cycles */
+ mod_timer(&clock_timer, jiffies + HZ/10);
+
+ mmc_request_done(mmc, mrq);
+}
+
+/* send 8 clock bits after last command */
+static void scsd_timeout(unsigned long arg)
+{
+ if (sd_active)
+ return; /* nothing to do, next timeout will come */
+
+ /* send 8 clocks after last command */
+ sd_dev->send_clocks();
}
/* read the write protect switch */
static int scsd_get_ro(struct mmc_host *mmc)
{
DBG("%s\n",__FUNCTION__);
- /* can't distinguish between ro and rw */
- return 0;
+ return sd_dev->read_only();
}
/* set operating conditions for the host */
@@ -600,14 +612,29 @@
struct scsd_host *host = NULL;
DBG("%s\n",__FUNCTION__);
+ /* Pointer to device-specific functions */
+#ifdef CONFIG_MMC_SCSD
+ sd_dev = &supercard_functions;
+ if (sd_dev->detect_card()) {
+ printk(KERN_INFO "Supercard SD detected\n");
+ goto success;
+ }
+#endif
+
+ /* device not found */
+ printk(KERN_INFO "No SD device found\n");
+ return -ENODEV;
+
+success:
/* allocate host data structures */
mmc = mmc_alloc_host(sizeof(struct scsd_host), dev);
if (!mmc) {
return -ENOMEM;
}
- /* unlock the SD interface */
- scsd_unlock();
+ /* init timer structure */
+ init_timer(&clock_timer);
+ clock_timer.function = scsd_timeout;
/* populate host data structures */
mmc->ops = &scsd_ops;
@@ -687,5 +714,5 @@
module_init(scsd_init);
module_exit(scsd_exit);
-MODULE_DESCRIPTION("Supercard SD Driver");
+MODULE_DESCRIPTION("Nintendo DS SD Driver");
MODULE_LICENSE("GPL");
Index: scsd_s.S
===================================================================
RCS file: /cvsroot/dslinux/dslinux/linux-2.6.x/drivers/mmc/scsd_s.S,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- scsd_s.S 15 Aug 2006 17:21:20 -0000 1.3
+++ scsd_s.S 27 Aug 2006 16:31:27 -0000 1.4
@@ -1,148 +1,389 @@
- .TEXT
+/*
+ * linux/drivers/mmc/scsd_s.S - Supercard SD driver
+ *
+ * Copyright (C) 2006 Amadeus, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver must be in main memory (or if you are doing XIP) in the
+ * lower 16 MBytes of GBA ROM space.
+ *
+ * NOTE: this driver destroys the last 2 bytes of RAM in the GBA ROM space.
+ * You don't want to store valuable information here.
+ */
- at ------ IO ports
-.equ sd_comadd,0x9800000
-.equ sd_dataadd,0x9000000
-.equ sd_dataradd,0x9100000
+/* common macros for all NDS GBA ROM device drivers */
+#include <asm/arch/gbarom-macro.S>
- at ------void sd_crc16_s(u16* buff,u16 num,u16* crc16buff)
- .ALIGN
- .GLOBAL sd_crc16_s
- .CODE 32
-sd_crc16_s:
- stmfd r13!,{r4-r9}
- mov r9,r2
+ .TEXT
- mov r3,#0
- mov r4,#0
- mov r5,#0
- mov r6,#0
+/*****************************************************************************/
+/* IO registers */
+#define SC_SD_CMD 0x09800000
+ /* bit 0: data bit to read */
+ /* bit 7: data bit to write */
- ldr r7,=0x80808080
- ldr r8,=0x1021
- mov r1,r1,lsl #3
-sd_crc16_loop:
+#define SC_SD_DATAWRITE 0x09000000
+#define SC_SD_DATAREAD 0x09100000
+#define SC_SDL_DOWRITE 0x09440000
+ /* SC lite: write 0 before write command */
- tst r7,#0x80
- ldrneb r2,[r0],#1
+#define SC_SD_LOCK 0x09FFFFFE
+ /* bit 0: 1 */
+ /* bit 1: enable IO interface (SD,CF) */
+ /* bit 2: enable R/W SDRAM access */
+#define SC_SD_PATTERN 0xA55A
- mov r3,r3,lsl #1
- tst r3,#0x10000
- eorne r3,r3,r8
- tst r2,r7,lsr #24
- eorne r3,r3,r8
-
- mov r4,r4,lsl #1
- tst r4,#0x10000
- eorne r4,r4,r8
- tst r2,r7,lsr #25
- eorne r4,r4,r8
+/*****************************************************************************/
+
+/* Switch GBA ROM space of supercard to IO mode.
+ * Only registers R3 and IP are used.
+ * RAM content @ SC_SD_LOCK destroyed.
+ */
+ .macro switch_io
+ ldr r3, =SC_SD_LOCK
+ ldr ip, =SC_SD_PATTERN
+ strh ip, [r3]
+ strh ip, [r3]
+ mov ip, #7 @ to be compatible - lower 16 MByte == RAM
+ strh ip, [r3]
+ strh ip, [r3]
+ .endm
- mov r5,r5,lsl #1
- tst r5,#0x10000
- eorne r5,r5,r8
- tst r2,r7,lsr #26
- eorne r5,r5,r8
+/* Switch GBA ROM space of supercard to RAM mode.
+ * Only registers R3 and IP are used.
+ * RAM content @ SC_SD_LOCK destroyed.
+ */
+ .macro switch_ram
+ ldr r3, =SC_SD_LOCK
+ ldr ip, =SC_SD_PATTERN
+ strh ip, [r3]
+ strh ip, [r3]
+ mov ip, #5 @ all 32 MBytes to RAM mode.
+ strh ip, [r3]
+ strh ip, [r3]
+ .endm
- mov r6,r6,lsl #1
- tst r6,#0x10000
- eorne r6,r6,r8
- tst r2,r7,lsr #27
- eorne r6,r6,r8
-
- mov r7,r7,ror #4
- subs r1,r1,#4
- bne sd_crc16_loop
+/*****************************************************************************/
- mov r2,r9
- mov r8,#16
-sd_crc16_write_data:
- mov r7,r7,lsl #4
- tst r3,#0x8000
- orrne r7,r7,#8
- tst r4,#0x8000
- orrne r7,r7,#4
- tst r5,#0x8000
- orrne r7,r7,#2
- tst r6,#0x8000
- orrne r7,r7,#1
+ @ Test if the card is present.
+ @ This test is tricky because if it's NOT this card,
+ @ we are not allowed to destroy contents of GBA ROM space.
+ @ R0: Return != 0 if present.
+ .ALIGN
+detect_card:
+ prefix
+ @ read old value @ SC_SD_CMD (in RAM)
+ ldr r3, =SC_SD_CMD
+ ldrh r2, [r3]
+ @ store opposite of requested value in SC_SD_CMD (in RAM)
+ mov r0, #-1
+ strh r0, [r3]
+ @ read old value @ SC_SD_LOCK (in RAM)
+ ldr r3, =SC_SD_LOCK
+ ldrh r1, [r3]
+ @ now switch to IO mode (destroy RAM @ SC_SD_LOCK)
+ switch_io
+ @ now read SC_SD_CMD (in IO)
+ ldr r3, =SC_SD_CMD
+ ldrh r0, [r3]
+ tst r0, #0x300
+ moveq r0, #1
+ movne r0, #0
+ @ switch back to RAM
+ switch_ram
+ @ restore RAM contents
+ ldr r3, =SC_SD_CMD
+ strh r2, [r3]
+ ldr r3, =SC_SD_LOCK
+ strh r1, [r3]
+ suffix
+ mov pc, lr
- mov r3,r3,lsl #1
- mov r4,r4,lsl #1
- mov r5,r5,lsl #1
- mov r6,r6,lsl #1
+/*****************************************************************************/
- sub r8,r8,#1
- tst r8,#1
- swpeqb r9,r7,[r2] @ don't use strb here
- addeq r2,r2,#1
- cmp r8,#0
- bne sd_crc16_write_data
+ @ Say if the data transfer is 1 or 4 bit.
+ @ R0: Return != 0 if 4 bit.
+ .ALIGN
+transfer_nibbles:
+ mov r0, #1 @ we do only 4 bit data transfers.
+ mov pc, lr
- ldmfd r13!,{r4-r9}
- bx r14
- at ------end sd_crc16_s-----------------------------------
+/*****************************************************************************/
- at -----------------void sd_data_write_s(u16 *buff, u32 length)
- .ALIGN
- .GLOBAL sd_data_write_s
- .CODE 32
-sd_data_write_s:
- stmfd r13!,{r2-r4}
- mov r2,#sd_dataadd
-sd_data_write_loop:
- ldrh r3,[r0],#2
- add r3,r3,r3,lsl #20
- mov r4,r3,lsr #8
- stmia r2,{r3-r4}
- subs r1,r1,#2
- bne sd_data_write_loop
- ldmfd r13!,{r2-r4}
- bx r14
- at -----------------end sd_data_write_s-------------------
+ @ Write at minimum 8 clock cycles to the card.
+ @ Wait max. 1ms for the CMD line to become HIGH.
+ @ Send a command to the card. Skip 2 Z bits.
+ @ R0: pointer to start of command. 32bit aligned.
+ @ R1: length of the command (including CRC7).
+ @ R0: Return != 0 if OK, 0 if timeout.
+ .ALIGN
+send_command:
+ stmfd sp!,{r4-r6} @ use additional registers
+ prefix
+ switch_io
+ ldr r2,=SC_SD_CMD
+ ldmia r2,{r3-r6} @ write 8 clocks
+ mov r4, #1024 @ max. loop count
+send_command_busy:
+ subs r4, r4, #1 @ dec. loop count
+ moveq r0, #0 @ exit R0=0
+ beq send_command_exit
+ ldrh r3,[r2]
+ tst r3,#0x1
+ beq send_command_busy
+ ldrh r3,[r2] @ one additional clock needed here(?)
+ @ supercard lite: write 0 before write command
+ ldrb r3,[r0] @ R3 = command byte
+ cmp r3,#(0x40+24) @ write single sector
+ cmpne r3,#(0x40+25) @ write multiple sectors
+ ldreq ip,=SC_SDL_DOWRITE
+ streqh ip, [ip]
+send_command_loop:
+ ldrb r3,[r0],#1 @ R3 = byte to send
+ add r3,r3,r3,lsl #17 @ some bit stuffing magic for supercard
+ mov r4,r3,lsl #2
+ mov r5,r4,lsl #2
+ mov r6,r5,lsl #2
+ stmia r2,{r3-r6} @ send 8 bit, one bit per 16 bit write
+ subs r1, r1, #1
+ bne send_command_loop
+ ldr r3,[r2] @ skip 2 Z bits
+ mov r0, #1 @ OK
+send_command_exit:
+ switch_ram
+ suffix
+ ldmfd sp!,{r4-r6} @ restore used registers
+ mov pc, lr
- at ----------void sd_data_read_s(u16 *buff, u32 length)
- .ALIGN
- .GLOBAL sd_data_read_s
- .CODE 32
-sd_data_read_s:
- stmfd r13!,{r2-r4}
- mov r2,#sd_dataradd
-sd_data_read_loop:
- ldmia r2,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
+/*****************************************************************************/
- ldmia r2,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
+ @ Wait max. 1ms for the CMD line to become LOW.
+ @ Read a response from the device and skip 2 Z bits.
+ @ R0: pointer to start of response buffer. 32bit aligned.
+ @ R1: number of bytes to read(including CRC).
+ @ R0: Return != 0 if OK, 0 if timeout.
+ .ALIGN
+read_response:
+ prefix
+ switch_io
+ ldr r2, =SC_SD_CMD
+ mov ip, #1024
+read_response_wait:
+ subs ip, ip, #1 @ dec. loop count
+ moveq r0, #0 @ exit R0=0
+ beq read_response_exit
+ ldrh r3,[r2]
+ tst r3,#0x1
+ bne read_response_wait
+ mov ip, #0 @ the first bit is 0
+ ldrh r3,[r2]
+ tst r3,#0x1
+ b read_response_7bit @ and begin in the middle
+read_response_loop:
+ mov ip, #0 @ read 8 bit from CMD line
+ ldr r3,[r2]
+ tst r3, #0x00000001
+ orrne ip, ip, #0x80
+ tst r3, #0x00010000
+read_response_7bit:
+ orrne ip, ip, #0x40
+ ldr r3,[r2]
+ tst r3, #0x00000001
+ orrne ip, ip, #0x20
+ tst r3, #0x00010000
+ orrne ip, ip, #0x10
+ ldr r3,[r2]
+ tst r3, #0x00000001
+ orrne ip, ip, #0x08
+ tst r3, #0x00010000
+ orrne ip, ip, #0x04
+ ldr r3,[r2]
+ tst r3, #0x00000001
+ orrne ip, ip, #0x02
+ tst r3, #0x00010000
+ orrne ip, ip, #0x01
+ strb ip,[r0],#1 @ store byte in buffer (main memory)
+ subs r1, r1, #1
+ bne read_response_loop
+ ldr r3,[r2] @ skip 2 Z bits
+ mov r0, #1 @ R0=OK
+read_response_exit:
+ switch_ram
+ suffix
+ mov pc, lr
- ldmia r2,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
+/*****************************************************************************/
- ldmia r2,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
+ @ Wait for the DATA line to become HIGH.
+ @ R0: Return != 0 if OK, 0 if timeout.
+ @ Maximum length of testing is 1ms.
+ .ALIGN
+wait_ready:
+ prefix
+ switch_io
+ ldr r1,=SC_SD_DATAREAD @ IO address
+ mov r2, #1024 @ number of tries
+wait_ready_again:
+ mov r3, #8 @ high counter
+wait_ready_loop:
+ subs r2, r2, #1 @ dec. loop count
+ moveq r0, #0 @ exit R0=0
+ beq wait_ready_exit
+ ldrh r0,[r1] @ read DATA line
+ tst r0, #0x100
+ beq wait_ready_again @ low: once more
+ subs r3, r3, #1 @ high: dec high counter
+ bne wait_ready_loop @ test again
+ @ 8 times HIGH - OK!
+ mov r0, #1 @ R0=OK
+wait_ready_exit:
+ switch_ram
+ suffix
+ mov pc, lr
- subs r1, r1, #8
- bne sd_data_read_loop
+/*****************************************************************************/
- ldmfd r13!,{r2-r4}
- bx r14
- at ----------end sd_data_read_s-------------
+ @ Write a start bit, send a Data block incl. CRC.
+ @ Write the end bit. Skip 2 Z bits.
+ @ Wait max. 1ms for the start of the CRC response.
+ @ Check the CRC response.
+ @ R0: pointer to start of data. 32bit aligned.
+ @ R1: number of bytes to send.
+ @ R0: Return != 0 if OK, 0 if CRC missing or error. */
+ .ALIGN
+send_data:
+ prefix
+ switch_io
+ @ write the start bit (0)
+ ldr ip,=SC_SD_DATAWRITE
+ strh ip, [ip]
+send_data_loop:
+ ldrh r2,[r0],#2 @ read 16 bit
+ add r2,r2,r2,lsl #20
+ mov r3,r2,lsr #8
+ stmia ip,{r2-r3}
+ subs r1,r1,#2
+ bne send_data_loop
+ @ write the end bit
+ ldr r2,=-1
+ strh r2,[ip]
+ @ switch to read mode
+ ldr ip,=SC_SD_DATAREAD
+ @ skip 2 Z bits
+ ldr r2,[ip]
+ mov r3, #1024
+send_data_wait:
+ subs r3, r3, #1 @ dec. loop count
+ moveq r0, #0 @ exit R0=0
+ beq send_data_exit
+ ldrh r2,[ip]
+ tst r2, #0x100
+ bne send_data_wait
+ @ read CRC response and end bit
+ mov r0, #0 @ failure code
+ ldr r2,[ip]
+ ldr r2,[ip] @ 1=bit28, 2=bit24, 3=bit20, end=bit16
+ tst r2, #0x10000000
+ bne send_data_exit
+ tst r2, #0x01000000
+ movne r0, #1 @ R0=OK if CRC code == 2 or 3
+send_data_exit:
+ switch_ram
+ suffix
+ mov pc, lr
+/*****************************************************************************/
+ @ Wait max 1ms for the DATA line to become LOW.
+ @ Receive a Data block and CRC, skip the end bit.
+ @ R0: pointer to start of data. 32bit aligned.
+ @ R1: number of bytes to receive (incl. CRC)
+ @ R0: Return != 0 if OK, 0 if timeout.
+ .ALIGN
+read_data:
+ prefix
+ switch_io
+ ldr ip,=SC_SD_DATAREAD
+ mov r2, #1024
+read_data_wait:
+ subs r2, r2, #1 @ dec. loop count
+ moveq r0, #0 @ exit R0=0
+ beq read_data_exit
+ ldrh r3,[ip]
+ tst r3,#0x100
+ bne read_data_wait
+read_data_loop:
+ ldmia ip,{r2-r3}
+ mov r2,r3,lsr #16
+ strh r2 ,[r0],#2
- .END
+ ldmia ip,{r2-r3}
+ mov r2,r3,lsr #16
+ strh r2 ,[r0],#2
+ ldmia ip,{r2-r3}
+ mov r2,r3,lsr #16
+ strh r2 ,[r0],#2
+ ldmia ip,{r2-r3}
+ mov r2,r3,lsr #16
+ strh r2 ,[r0],#2
+ subs r1, r1, #8
+ bne read_data_loop
+
+ ldrh r2,[ip] @ read the end bit
+ mov r0, #1 @ R0=OK
+read_data_exit:
+ switch_ram
+ suffix
+ mov pc, lr
+/*****************************************************************************/
+ @ Read the write protect switch.
+ @ R0: Return != 0 if readonly, 0 if r/w.
+ @ When in doubt, return 0.
+ .ALIGN
+read_only:
+ mov r0, #0 @ we cannot read the r/w switch
+ mov pc, lr
+/*****************************************************************************/
+ @ Write at minimum 8 clock cycles to the card.
+ .ALIGN
+send_clocks:
+ prefix
+ switch_io
+ ldr r0,=SC_SD_CMD
+ ldr r1,[r0]
+ ldr r1,[r0]
+ ldr r1,[r0]
+ ldr r1,[r0]
+ switch_ram
+ suffix
+ mov pc, lr
+/*****************************************************************************/
+ @ Structure for device-specific functions in Assembler.
+ .GLOBAL supercard_functions
+ .ALIGN
+supercard_functions:
+ .word detect_card
+ .word transfer_nibbles
+ .word send_command
+ .word read_response
+ .word wait_ready
+ .word send_data
+ .word read_data
+ .word read_only
+ .word send_clocks
+ .END
+/*****************************************************************************/
More information about the dslinux-commit
mailing list