dslinux/linux-2.6.x/drivers/mmc scsd_c.c scsd_s.S
amadeus
dslinux_amadeus at user.in-berlin.de
Wed Aug 30 14:05:28 CEST 2006
Update of /cvsroot/dslinux/dslinux/linux-2.6.x/drivers/mmc
In directory antilope:/tmp/cvs-serv4723/linux-2.6.x/drivers/mmc
Modified Files:
scsd_c.c scsd_s.S
Log Message:
Optimizing switched SD driver
Index: scsd_c.c
===================================================================
RCS file: /cvsroot/dslinux/dslinux/linux-2.6.x/drivers/mmc/scsd_c.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- scsd_c.c 27 Aug 2006 16:31:27 -0000 1.5
+++ scsd_c.c 30 Aug 2006 12:05:26 -0000 1.6
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/scsd_c.c - Nintendo DS SD driver
+ * linux/drivers/mmc/scsd_c.c - Supercard SD driver
*
* Copyright (C) 2006 Amadeus, All Rights Reserved.
* Based on the old non-mmc driver by by Jean-Pierre Thomasset.
@@ -48,7 +48,7 @@
#define BLOCKSIZE 512
#define DRIVER_NAME "scsd"
-#define DRIVER_VERSION "1.1.2"
+#define DRIVER_VERSION "1.1.3"
/*****************************************************************************/
@@ -58,66 +58,56 @@
};
/*****************************************************************************/
-/* 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);
+/*
+ * Low-level assembler stuff in scsd_s.S
+ */
- /* 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);
+/* Test if the card is present.
+ Return != 0 if present. */
+extern int scsd_detect_card(void);
- /* 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 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.
+ if reslen > 0:
+ 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 command & response. 32bit aligned.
+ len = length of the command (including CRC7).
+ reslen = length of response.
+ Return 0 if OK, 1 if timeout waiting for CMD HIGH,
+ 2 if timeout waiting for CMD LOW */
+extern int scsd_send_command_resp(u8 *data, int len, int reslen);
- /* 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 for the DATA line to become HIGH.
+ Return != 0 if OK, 0 if timeout.
+ Maximum length of testing is 1ms. */
+extern int scsd_wait_ready(void);
- /* 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);
+/* 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. */
+extern int scsd_send_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);
+/* 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. */
+extern int scsd_read_data(u8 *data, int len);
- /* Write at minimum 8 clock cycles to the card. */
- void (*send_clocks) (void);
-};
+/* Write at minimum 8 clock cycles to the card. */
+extern void scsd_send_clocks(void);
-/*****************************************************************************/
-/* Active link to device-specific functions.
-*/
-static struct sd_functions *sd_dev;
+/* 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. */
+extern void scsd_calc_crc(u8 *data, int len, u8* crc);
/*****************************************************************************/
/* Timer delayed execution of last clocks */
@@ -132,14 +122,6 @@
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)
@@ -162,85 +144,6 @@
return(crc);
}
-/* 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)
-{
- __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");
-}
-
/* Wait until ready on the data lines */
/* return 0 if ready, 1 if busy */
@@ -249,7 +152,7 @@
int i;
for (i = 1000; i; i--) {
- if (sd_dev->wait_ready())
+ if (scsd_wait_ready())
return 0;
}
return 1;
@@ -261,6 +164,7 @@
{
u8 *p = sd_databuf;
int i;
+ int reslen;
/* stop the clock timer, we will send a command */
del_timer(&clock_timer);
@@ -276,10 +180,29 @@
*p++ = cmd->arg;
*p = scsd_crc7(sd_databuf, 5);
- /* waiting for CMD line high, write command to card */
+ /* calculate length of response */
+ reslen = 0;
+ if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_LONG)
+ reslen = 18;
+ if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT)
+ reslen = 6;
+ if ((cmd->opcode == MMC_READ_SINGLE_BLOCK)
+ || (cmd->opcode == MMC_READ_MULTIPLE_BLOCK)
+ || (cmd->opcode == SD_APP_SEND_SCR))
+ reslen = 0;
+ /* waiting for CMD line high, write command to card, read response */
for (i = 250; i; i--) {
- if (sd_dev->send_command(sd_databuf, 6))
+ int ret = scsd_send_command_resp(sd_databuf, 6, reslen);
+ if (!ret) /* all OK */
break;
+ if (ret == 1) /* Card busy, try again */
+ continue;
+ if (ret == 2) { /* Timeout waiting for response */
+ /* Timeout error */
+ printk(KERN_ERR "CMD:Timeout after command\n");
+ cmd->error = MMC_ERR_TIMEOUT;
+ return -1;
+ }
}
if (!i) {
printk( KERN_ERR "CMD:Timeout before command\n");
@@ -307,17 +230,6 @@
return 0;
}
- /* 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 "CMD:Timeout after command\n");
- cmd->error = MMC_ERR_TIMEOUT;
- return -1;
- }
p = sd_databuf;
p++; /* skip command byte */
cmd->resp[0] = *p++ << 24;
@@ -361,7 +273,6 @@
}
/* success */
- cmd->error = MMC_ERR_NONE;
return 0;
}
@@ -404,7 +315,7 @@
/* 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))
+ if (scsd_read_data(sd_databuf, length+8))
break;
}
if (!i) {
@@ -447,7 +358,7 @@
}
/* Write data, check CRC response */
- if (!sd_dev->send_data(sd_databuf, length+8)) {
+ if (!scsd_send_data(sd_databuf, length+8)) {
/* Timeout error */
printk(KERN_ERR "BAD CRC response\n");
data->error = MMC_ERR_TIMEOUT;
@@ -493,7 +404,7 @@
/* Fooling mmc core to only do 4bit data transfers.
if the hardware/the driver can only do 4bit transfers. */
- if (sd_dev->transfer_nibbles() && mmc->card_selected) {
+ if (mmc->card_selected) {
mmc->card_selected->scr.bus_widths |= SD_SCR_BUS_WIDTH_4;
}
@@ -565,14 +476,14 @@
return; /* nothing to do, next timeout will come */
/* send 8 clocks after last command */
- sd_dev->send_clocks();
+ scsd_send_clocks();
}
/* read the write protect switch */
static int scsd_get_ro(struct mmc_host *mmc)
{
DBG("%s\n",__FUNCTION__);
- return sd_dev->read_only();
+ return 0;
}
/* set operating conditions for the host */
@@ -612,20 +523,14 @@
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()) {
+ if (scsd_detect_card()) {
printk(KERN_INFO "Supercard SD detected\n");
- goto success;
+ } else {
+ /* device not found */
+ printk(KERN_INFO "No Supercard SD found\n");
+ return -ENODEV;
}
-#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) {
@@ -714,5 +619,5 @@
module_init(scsd_init);
module_exit(scsd_exit);
-MODULE_DESCRIPTION("Nintendo DS SD Driver");
+MODULE_DESCRIPTION("Supercard 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.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- scsd_s.S 28 Aug 2006 18:49:08 -0000 1.5
+++ scsd_s.S 30 Aug 2006 12:05:26 -0000 1.6
@@ -9,9 +9,6 @@
*
* 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.
*/
/* common macros for all NDS GBA ROM device drivers */
@@ -37,42 +34,29 @@
@ we are not allowed to destroy contents of GBA ROM space.
@ R0: Return != 0 if present.
.ALIGN
-detect_card:
- prefix
+ .GLOBAL scsd_detect_card
+scsd_detect_card:
+ gba_prefix
@ read old value @ SC_SD_CMD (in RAM)
ldr r3, =SC_SD_CMD
- ldrh r2, [r3]
+ ldrh r1, [r3]
@ store opposite of requested value in SC_SD_CMD (in RAM)
mov r0, #-1
strh r0, [r3]
- @ read old value @ SC_LOCK (in RAM)
- ldr r3, =SC_LOCK
- ldrh r1, [r3]
- @ now switch to IO mode (destroy RAM @ SC_SD_LOCK)
- sc_setmode SC_MODE_IO
+ @ now switch to IO mode (save old value @SC_LOCK in R2)
+ sc_set_io
@ now read SC_SD_CMD (in IO)
ldr r3, =SC_SD_CMD
ldrh r0, [r3]
- tst r0, #0x300
+ tst r0, #0x300 @ both bits must be 0
moveq r0, #1
movne r0, #0
- @ switch back to RAM
- sc_setmode SC_MODE_RAM
+ @ switch back to RAM (restore old value @SC_LOCK from R2)
+ sc_set_ram
@ restore RAM contents
ldr r3, =SC_SD_CMD
- strh r2, [r3]
- ldr r3, =SC_LOCK
- strh r1, [r3]
- suffix
- mov pc, lr
-
-/*****************************************************************************/
-
- @ 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.
+ strh r1, [r3]
+ gba_suffix
mov pc, lr
/*****************************************************************************/
@@ -80,103 +64,98 @@
@ 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.
+ @ if R2 > 0:
+ @ 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 command & response. 32bit aligned.
@ R1: length of the command (including CRC7).
- @ R0: Return != 0 if OK, 0 if timeout.
+ @ R2: length of response.
+ @ R0 Return 0 if OK, 1 if timeout waiting for CMD HIGH,
+ @ 2 if timeout waiting for CMD LOW
.ALIGN
-send_command:
- stmfd sp!,{r4-r6} @ use additional registers
- prefix
- sc_setmode SC_MODE_IO
- ldr r2,=SC_SD_CMD
- ldmia r2,{r3-r6} @ write 8 clocks
+ .GLOBAL scsd_send_command_resp
+scsd_send_command_resp:
+ stmfd sp!,{r4-r8} @ use additional registers
+ gba_prefix
+ mov r8, r2 @ store 3rd parameter in R8
+ sc_set_io @ switch to IO mode, save @SC_LOCK in R2
+ ldr r7,=SC_SD_CMD
+ ldmia r7,{r3-r6} @ write 8 clocks
mov r4, #1024 @ max. loop count
-send_command_busy:
+scsd_send_command_busy:
subs r4, r4, #1 @ dec. loop count
- moveq r0, #0 @ exit R0=0
- beq send_command_exit
- ldrh r3,[r2]
+ moveq r0, #1 @ exit R0=1
+ beq scsd_send_command_exit
+ ldrh r3,[r7]
tst r3,#0x1
- beq send_command_busy
- ldrh r3,[r2] @ one additional clock needed here(?)
+ beq scsd_send_command_busy
+ ldrh r3,[r7] @ 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
+ mov ip, r0
+scsd_send_command_loop:
+ ldrb r3,[ip],#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
+ stmia r7,{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:
- sc_setmode SC_MODE_RAM
- suffix
- ldmfd sp!,{r4-r6} @ restore used registers
- mov pc, lr
-
-/*****************************************************************************/
-
- @ 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
- sc_setmode SC_MODE_IO
- ldr r2, =SC_SD_CMD
+ bne scsd_send_command_loop
+ ldr r3,[r7] @ skip 2 Z bits
+ @ test if we have to read a response
+ teq r8, #0 @ reslen = 0?
+ beq scsd_send_command_ok @ yes: no response please
+ @ wait for CMD line LOW
mov ip, #1024
-read_response_wait:
+scsd_read_response_wait:
subs ip, ip, #1 @ dec. loop count
- moveq r0, #0 @ exit R0=0
- beq read_response_exit
- ldrh r3,[r2]
+ moveq r0, #2 @ exit R0=2
+ beq scsd_send_command_exit
+ ldrh r3,[r7]
tst r3,#0x1
- bne read_response_wait
+ bne scsd_read_response_wait
mov ip, #0 @ the first bit is 0
- ldrh r3,[r2]
+ ldrh r3,[r7]
tst r3,#0x1
- b read_response_7bit @ and begin in the middle
-read_response_loop:
+ b scsd_read_response_7bit @ and begin in the middle
+scsd_read_response_loop:
mov ip, #0 @ read 8 bit from CMD line
- ldr r3,[r2]
+ ldr r3,[r7]
tst r3, #0x00000001
orrne ip, ip, #0x80
tst r3, #0x00010000
-read_response_7bit:
+scsd_read_response_7bit:
orrne ip, ip, #0x40
- ldr r3,[r2]
+ ldr r3,[r7]
tst r3, #0x00000001
orrne ip, ip, #0x20
tst r3, #0x00010000
orrne ip, ip, #0x10
- ldr r3,[r2]
+ ldr r3,[r7]
tst r3, #0x00000001
orrne ip, ip, #0x08
tst r3, #0x00010000
orrne ip, ip, #0x04
- ldr r3,[r2]
+ ldr r3,[r7]
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:
- sc_setmode SC_MODE_RAM
- suffix
+ subs r8, r8, #1
+ bne scsd_read_response_loop
+ ldr r3,[r7] @ skip 2 Z bits
+scsd_send_command_ok:
+ mov r0, #0 @ OK
+scsd_send_command_exit:
+ sc_set_ram @ swith to RAM mode, restore @SC_LOCK from R2
+ gba_suffix
+ ldmfd sp!,{r4-r8} @ restore used registers
mov pc, lr
/*****************************************************************************/
@@ -185,27 +164,27 @@
@ R0: Return != 0 if OK, 0 if timeout.
@ Maximum length of testing is 1ms.
.ALIGN
-wait_ready:
- prefix
- sc_setmode SC_MODE_IO
+ .GLOBAL scsd_wait_ready
+scsd_wait_ready:
+ gba_prefix
+ sc_set_io @ switch to IO mode, save @SC_LOCK in R2
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
+ mov ip, #1024 @ number of tries
+scsd_wait_ready_again:
+ mov r3, #8 @ high times counter
+scsd_wait_ready_loop:
+ subs ip, ip, #1 @ dec. loop count
moveq r0, #0 @ exit R0=0
- beq wait_ready_exit
+ beq scsd_wait_ready_exit
ldrh r0,[r1] @ read DATA line
tst r0, #0x100
- beq wait_ready_again @ low: once more
+ beq scsd_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:
- sc_setmode SC_MODE_RAM
- suffix
+ bne scsd_wait_ready_loop @ test again
+ mov r0, #1 @ 8 times HIGH - OK!
+scsd_wait_ready_exit:
+ sc_set_ram @ swith to RAM mode, restore @SC_LOCK from R2
+ gba_suffix
mov pc, lr
/*****************************************************************************/
@@ -218,45 +197,48 @@
@ R1: number of bytes to send.
@ R0: Return != 0 if OK, 0 if CRC missing or error. */
.ALIGN
-send_data:
- prefix
- sc_setmode SC_MODE_IO
+ .GLOBAL scsd_send_data
+scsd_send_data:
+ stmfd sp!,{r4} @ use additional registers
+ gba_prefix
+ sc_set_io @ switch to IO mode, save @SC_LOCK in R2
@ 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}
+scsd_send_data_loop:
+ ldrh r3,[r0],#2 @ read 16 bit
+ add r3,r3,r3,lsl #20
+ mov r4,r3,lsr #8
+ stmia ip,{r3-r4}
subs r1,r1,#2
- bne send_data_loop
+ bne scsd_send_data_loop
@ write the end bit
- ldr r2,=-1
- strh r2,[ip]
+ ldr r3,=-1
+ strh r3,[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
+ ldr r3,[ip]
+ mov r4, #1024
+scsd_send_data_wait:
+ subs r4, r4, #1 @ dec. loop count
moveq r0, #0 @ exit R0=0
- beq send_data_exit
- ldrh r2,[ip]
- tst r2, #0x100
- bne send_data_wait
+ beq scsd_send_data_exit
+ ldrh r3,[ip]
+ tst r3, #0x100
+ bne scsd_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
+ ldr r3,[ip]
+ ldr r3,[ip] @ 1=bit28, 2=bit24, 3=bit20, end=bit16
+ tst r3, #0x10000000
+ bne scsd_send_data_exit
+ tst r3, #0x01000000
movne r0, #1 @ R0=OK if CRC code == 2 or 3
-send_data_exit:
- sc_setmode SC_MODE_RAM
- suffix
+scsd_send_data_exit:
+ sc_set_ram @ swith to RAM mode, restore @SC_LOCK from R2
+ gba_suffix
+ ldmfd sp!,{r4} @ restore used registers
mov pc, lr
/*****************************************************************************/
@@ -267,86 +249,144 @@
@ R1: number of bytes to receive (incl. CRC)
@ R0: Return != 0 if OK, 0 if timeout.
.ALIGN
-read_data:
- prefix
- sc_setmode SC_MODE_IO
+ .GLOBAL scsd_read_data
+scsd_read_data:
+ stmfd sp!,{r4} @ use additional registers
+ gba_prefix
+ sc_set_io @ switch to IO mode, save @SC_LOCK in R2
ldr ip,=SC_SD_DATAREAD
- mov r2, #1024
-read_data_wait:
- subs r2, r2, #1 @ dec. loop count
+ mov r3, #1024
+scsd_read_data_wait:
+ subs r3, r3, #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
+ beq scsd_read_data_exit
+ ldrh r4,[ip]
+ tst r4,#0x100
+ bne scsd_read_data_wait
+scsd_read_data_loop:
+ ldmia ip,{r3-r4}
+ mov r3,r4,lsr #16
+ strh r3 ,[r0],#2
- ldmia ip,{r2-r3}
- mov r2,r3,lsr #16
- strh r2 ,[r0],#2
+ ldmia ip,{r3-r4}
+ mov r3,r4,lsr #16
+ strh r3 ,[r0],#2
- ldmia ip,{r2-r3}
- mov r2,r3,lsr #16
- strh r2 ,[r0],#2
+ ldmia ip,{r3-r4}
+ mov r3,r4,lsr #16
+ strh r3 ,[r0],#2
- ldmia ip,{r2-r3}
- mov r2,r3,lsr #16
- strh r2 ,[r0],#2
+ ldmia ip,{r3-r4}
+ mov r3,r4,lsr #16
+ strh r3 ,[r0],#2
subs r1, r1, #8
- bne read_data_loop
+ bne scsd_read_data_loop
- ldrh r2,[ip] @ read the end bit
- mov r0, #1 @ R0=OK
-read_data_exit:
- sc_setmode SC_MODE_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
+ ldrh r3,[ip] @ read the end bit
+ mov r0, #1 @ R0=OK
+scsd_read_data_exit:
+ sc_set_ram @ swith to RAM mode, restore @SC_LOCK from R2
+ gba_suffix
+ ldmfd sp!,{r4} @ restore used registers
mov pc, lr
/*****************************************************************************/
@ Write at minimum 8 clock cycles to the card.
.ALIGN
-send_clocks:
- prefix
- sc_setmode SC_MODE_IO
+ .GLOBAL scsd_send_clocks
+scsd_send_clocks:
+ gba_prefix
+ sc_set_io @ switch to IO mode, save @SC_LOCK in R2
ldr r0,=SC_SD_CMD
ldr r1,[r0]
ldr r1,[r0]
ldr r1,[r0]
ldr r1,[r0]
- sc_setmode SC_MODE_RAM
- suffix
+ sc_set_ram @ switch to RAM mode, restore @SC_LOCK from R2
+ gba_suffix
mov pc, lr
/*****************************************************************************/
- @ Structure for device-specific functions in Assembler.
- .GLOBAL supercard_functions
+ @ Calculate the data crc.
+ @ R0: pointer to start of data. 32bit aligned.
+ @ R1: number of bytes of CRC calculation.
+ @ R2: pointer to start of CRC.
.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
+ .GLOBAL scsd_calc_crc
+scsd_calc_crc:
+ stmfd sp!,{r4-r9}
+ mov r9,r2
+
+ mov r3,#0
+ mov r4,#0
+ mov r5,#0
+ mov r6,#0
+
+ ldr r7,=0x80808080
+ ldr r8,=0x1021
+ mov r1,r1,lsl #3
+scsd_calc_crc_loop:
+
+ tst r7,#0x80
+ ldrneb r2,[r0],#1
+
+ 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
+
+ mov r5,r5,lsl #1
+ tst r5,#0x10000
+ eorne r5,r5,r8
+ tst r2,r7,lsr #26
+ eorne r5,r5,r8
+
+ 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 scsd_calc_crc_loop
+
+ mov r2,r9
+ mov r8,#16
+scsd_calc_crc_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
+
+ 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
+ streqb r7,[r2], #1
+ cmp r8,#0
+ bne scsd_calc_crc_write_data
+
+ ldmfd sp!,{r4-r9}
+ mov pc, lr
.END
More information about the dslinux-commit
mailing list