dslinux/linux-2.6.x/drivers/mmc m3sd_c.c m3sd_s.S

amadeus dslinux_amadeus at user.in-berlin.de
Sun Sep 17 00:35:25 CEST 2006


Update of /cvsroot/dslinux/dslinux/linux-2.6.x/drivers/mmc
In directory antilope:/tmp/cvs-serv20954/linux-2.6.x/drivers/mmc

Added Files:
	m3sd_c.c m3sd_s.S 
Log Message:
new M3SD driver

--- NEW FILE: m3sd_s.S ---
/*
 *  linux/drivers/mmc/m3sd_s.S - M3 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.
 */

/* common macros for all NDS GBA ROM device drivers */
#include <asm/arch/gbarom-macro.S>

    	.TEXT

/*****************************************************************************/
/* IO registers */

#define REG_M3SD_DIR	0x08800000	@ direction control register
#define REG_M3SD_DAT	0x09000000	@ SD data line, 8 bits at a time
#define REG_M3SD_CMD	0x09200000	@ SD command byte
#define REG_M3SD_ARGH	0x09400000	@ SD command argument, high halfword
#define REG_M3SD_ARGL	0x09600000	@ SD command argument, low halfword
#define REG_M3SD_STS	0x09800000	@ command and status register

/* LBA1 register of M3 CF */
#define REG_M3CF_LBA1	0x08860000	@ 1st byte of sector address

/*****************************************************************************/

	@ 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
	.GLOBAL m3sd_detect_card
m3sd_detect_card:	
	gba_prefix
	@ read and save old value @ REG_M3CF_LBA1
	ldr	r3, =REG_M3CF_LBA1
	ldrh	r2, [r3]
	ldr	r1, =0x789A		@ random value
	strh	r1, [r3]
	@ switch M3 to IO mode
	m3_set_io
	@ test if the value has remained the same
	ldr	r3, =REG_M3CF_LBA1
	ldrh	ip, [r3]
	teq	r1, ip
	moveq	r0, #0			@ YES: no M3
	beq	m3sd_detect_exit
	@ it's a M3. Test for CF. If not CF, it must be a SD.
	@ test if the lower 8 bit of LBA1 are read- and writable	
	ldrb	ip, [r3]
	eor	ip, ip, #0xFF		@ invert lower 8 bit of LBA1
	strh	ip, [r3]		@ store complement in LBA1
	ldrb	r0, [r3]
	teq	ip, r0			@ are they the same?
	movne	r0, #1			@ NO: no CF, must be SD
	bne	m3sd_detect_exit
	@ make sure the register is 8 bit, not 16
	ldr	ip, =0xAA55
	strh	ip, [r3]
	ldrh	r0, [r3]
	teq	ip, r0			@ are they the same?
	moveq	r0, #1			@ YES: no CF, must be SD
	movne	r0, #0			@ NO: it's a CF
m3sd_detect_exit:
	m3_set_ram			@ switch back to RAM
	@ restore RAM contents
	ldr	r3, =REG_M3CF_LBA1
	strh	r2, [r3]
	gba_suffix
	mov	pc, lr

/*****************************************************************************/
	@ macro to read a byte of response (from CMD line)

	@ register input:
	@ R3 = REG_M3SD_STS
	@ R4 = REG_M3SD_DIR

	@ register used:
	@ R5, CC

	@ register output:
	@ IP = byte to read

	@ error codes:
 	@ R0 = 3: timeout @ readbyte, first half
 	@ R0 = 4: timeout @ readbyte, 2nd half
 
	.macro	readbyte exitlabel
	mov	ip, #0x02
	strh	ip, [r4]		@ REG_M3SD_DIR
	strh	ip, [r3]		@ REG_M3SD_STS
 	mov	r5, #16384		@ timeout counter
1:	subs	r5, r5, #1
	moveq	r0, #3			@ exit R0=3
	beq	\exitlabel
	ldrh	ip, [r3]		@ REG_M3SD_STS
	tst	ip, #0x08
	beq	1b
	mov	r5, #16384		@ timeout counter
2:	subs	r5, r5, #1
	moveq	r0, #4			@ exit R0=4
	beq	\exitlabel
	ldrh	ip, [r3]		@ REG_M3SD_STS
	tst	ip, #0x08
	bne	2b
	ldr	r5, =REG_M3SD_DAT
	ldrb	ip, [r5]		@ get data byte
	.endm

/*****************************************************************************/

	@ 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.
	@ if R2 > 0:
   	@ Wait max. 1ms for the CMD line to become LOW.
   	@ Read a response from the device. 
        @ R0: pointer to start of command & response. 32bit aligned.
	@ R1: length of the command (including CRC7).
	@ R2: length of response.
   	@ R0 Return 0 if OK, 1 if timeout waiting for CMD HIGH,
	@                    2 if timeout waiting for CMD LOW 
 	@ 		     3 if timeout @ readbyte, first half
 	@                    4 if timeout @ readbyte, 2nd half
	@                    5 if timeout for M3 command processing
	.ALIGN
	.GLOBAL m3sd_send_command_resp
m3sd_send_command_resp:
	stmfd   sp!,{r4-r8}		@ use additional registers
	gba_prefix
	m3_set_io			@ switch to IO mode
	@ setup pointers to the most used card registers
	ldr	r3, =REG_M3SD_STS
	ldr	r4, =REG_M3SD_DIR
	@ Wait max. 1ms for the CMD line to become HIGH.
	@ this implies at minimum 8 clock cycles.
	mov	r6, #1024		@ retry counter
m3sd_send_command_cmdhigh:
	subs	r6, r6, #1
	moveq	r0, #1			@ exit R0=1
	beq	m3sd_send_command_exit
	readbyte m3sd_send_command_exit
	teq	ip, #0xFF		@ all bits high?
	bne	m3sd_send_command_cmdhigh
	@ Send a command to the card. 
	mov	ip, #0x08
	strh	ip, [r3]
	ldr	r5, =REG_M3SD_CMD
	ldrh	ip, [r0, #0]
	strh	ip, [r5]
	ldr	r5, =REG_M3SD_ARGH
	ldrh	ip, [r0, #2]
	strh	ip, [r5]
	ldr	r5, =REG_M3SD_ARGL
	ldrh	ip, [r0, #4]
	strh	ip, [r5]
	@ CRC is done by the M3.
	@ wait until M3 has processed the command.
	mov	ip, #0x29
	strh	ip, [r4]		@ REG_M3SD_DIR
	mov	r5, #16384		@ timeout counter
m3sd_send_command_proc:
	subs	r5, r5, #1
	moveq	r0, #0x09
	streqh	r0, [r4]		@ REG_M3SD_DIR
	moveq	r0, #5			@ exit R0=5
	beq	m3sd_send_command_exit
	ldrh	ip, [r3]		@ REG_M3SD_STS
	tst	ip, #0x01
	beq	m3sd_send_command_proc
	mov	ip, #0x09
	strh	ip, [r4]		@ REG_M3SD_DIR
	@ test if we have to read a response
	teq	r2, #0			@ reslen = 0?
	moveq	r0, #0			@ exit R0=0
	beq	m3sd_send_command_exit
	@ wait until start of response
	mov	r6, #256		@ max. byte count
m3sd_send_command_wait:
	subs	r6, r6, #1
	moveq	r0, #2			@ exit R0=2
	beq	m3sd_send_command_exit
	readbyte m3sd_send_command_exit
	teq	ip, #0xFF
	beq	m3sd_send_command_wait
	@ now we have the first bits of the response in IP
	@ align to first bit (==0)
	mov	r6, #8			@ shift count
	mov	r5, #0x80		@ test pattern
m3sd_send_command_align:
	tst	ip, r5			@ is this bit 0?
	movne	r5, r5, lsr #1
	subne	r6, r6, #1
	bne	m3sd_send_command_align
	mov	r7, ip			@ save byte in R7
	@ read bytes and store into response buffer
m3sd_read_response_loop:
	readbyte m3sd_send_command_exit
	orr	r7, ip, r7, lsl #8	@ shift data byte in R7
	mov	ip, r7, lsr r6		@ deshifting
	strb	ip, [r0], #1		@ store byte
	subs	r2, r2, #1
	bne	m3sd_read_response_loop
	mov	r0, #0			@ success code
	@ exit
m3sd_send_command_exit:
	m3_set_ram			@ swith to RAM mode
	gba_suffix
	ldmfd   sp!,{r4-r8}		@ restore used registers
	mov	pc, lr

/*****************************************************************************/

	@ Wait for the DATA line to become HIGH.
	@ R0: Return != 0 if OK, 0 if timeout.
	@ Maximum length of testing is 1ms.
	.ALIGN
	.GLOBAL m3sd_wait_ready
m3sd_wait_ready:
	gba_prefix
	m3_set_io			@ switch to IO mode
	ldr	r2, =REG_M3SD_DIR
	ldr	r1, =REG_M3SD_DAT
	mov	ip, #1024		@ number of tries
m3sd_wait_ready_again:
	mov	r3, #8			@ high times counter
m3sd_wait_ready_loop:
	subs	ip, ip, #1		@ dec. loop count
	moveq	r0, #0			@ exit R0=0
	beq	m3sd_wait_ready_exit
	mov	r0, #0x00
	strh	r0, [r2]		@ REG_M3SD_DIR
	mov	r0, r0			@ nop
	mov	r0, r0			@ nop
	mov	r0, #0x08
	strh	r0, [r2]		@ REG_M3SD_DIR
	ldrh	r0, [r1]		@ REG_M3SD_DAT
	tst	r0, #0x100
	beq	m3sd_wait_ready_again	@ low: once more
	subs	r3, r3, #1		@ high: dec high counter
	bne	m3sd_wait_ready_loop	@ test again
	mov	r0, #1			@ 8 times HIGH - OK!
m3sd_wait_ready_exit:
	m3_set_ram			@ swith to RAM mode
	gba_suffix
	mov	pc, lr

/*****************************************************************************/

	@ Send a Data block incl. CRC.
	@ 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
	.GLOBAL m3sd_send_data
m3sd_send_data:
	stmfd   sp!,{r4-r5}		@ use additional registers
	gba_prefix
	m3_set_io			@ switch to IO mode
	@ setup pointers to the most used card registers
	ldr	r3, =REG_M3SD_STS
	ldr	r4, =REG_M3SD_DIR
	ldr	r5, =REG_M3SD_DAT
	mov	ip, #0x04
	strh	ip, [r4]		@ REG_M3SD_DIR
	mov	ip, #0x00
	strh	ip, [r3]		@ REG_M3SD_STS
	@ start bit
	mov	ip, #0x00
	strh	ip, [r5]		@ REG_M3SD_DAT
	mov	ip, #0x04
	strh	ip, [r4]		@ REG_M3SD_DIR
	mov	ip, ip			@ nop
	mov	ip, ip			@ nop
	mov	ip, #0x0C
	strh	ip, [r4]		@ REG_M3SD_DIR
m3sd_send_data_loop:
	ldrb	ip, [r0], #1		@ read next byte
	mov	r2, ip, lsr #4		@ MSN
	strh	r2, [r5]		@ REG_M3SD_DAT
	mov	r2, #0x04
	strh	r2, [r4]		@ REG_M3SD_DIR
	mov	r2, r2			@ nop
	mov	r2, r2			@ nop
	mov	r2, #0x0C
	strh	r2, [r4]		@ REG_M3SD_DIR
	strh	ip, [r5]		@ REG_M3SD_DAT
	mov	r2, #0x04
	strh	r2, [r4]		@ REG_M3SD_DIR
	mov	r2, r2			@ nop
	mov	r2, r2			@ nop
	mov	r2, #0x0C
	strh	r2, [r4]		@ REG_M3SD_DIR
	subs	r1, r1, #1
	bne     m3sd_send_data_loop
	@ wait a little while
	mov	ip, #32
m3sd_send_wait:
	mov	r1, r1
	subs	ip, ip, #1
	bne	m3sd_send_wait
	@ send some FF
	mov	r1, #32
m3sd_send_FF:
	mov	ip, #0xFF
	strh	ip, [r5]		@ REG_M3SD_DAT
	mov	r2, #0x04
	strh	r2, [r4]		@ REG_M3SD_DIR
	mov	r2, r2			@ nop
	mov	r2, r2			@ nop
	mov	r2, #0x0C
	strh	r2, [r4]		@ REG_M3SD_DIR
	subs	r1, r1, #1
	bne     m3sd_send_FF
	mov	r0, #1			@ R0=OK
m3sd_send_data_exit:
	m3_set_ram			@ swith to RAM mode
	gba_suffix
	ldmfd   sp!,{r4-r5}		@ restore used registers
	mov	pc, lr

/*****************************************************************************/

	@ Wait max 1ms for the DATA line to become LOW.
	@ Receive a Data block and CRC.
	@ 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
	.GLOBAL m3sd_read_data
m3sd_read_data:
	stmfd   sp!,{r4-r8}		@ use additional registers
	gba_prefix
	m3_set_io			@ switch to IO mode
	@ setup pointers to the most used card registers
	ldr	r3, =REG_M3SD_STS
	ldr	r4, =REG_M3SD_DIR
	mov	r2, #0x49
	strh	r2, [r4]		@ REG_M3SD_DIR
	mov	r2, #1024
m3sd_read_data_wait:
	subs	r2, r2, #1		@ dec. loop count
	moveq	r2, #0x09
	streqh	r2, [r4]		@ REG_M3SD_DIR
	moveq	r0, #0			@ exit R0=0
	beq	m3sd_read_data_exit
	ldrh	ip, [r3]		@ REG_M3SD_STS
	tst	ip, #0x40
	beq	m3sd_read_data_wait
	mov	r2, #0x09
	strh	r2, [r4]		@ REG_M3SD_DIR
	mov	r2, #0x08
	strh	r2, [r4]		@ REG_M3SD_DIR
	mov	r2, #0x04
	strh	r2, [r3]		@ REG_M3SD_STS
	ldrh	r2, [r4]		@ REG_M3SD_DIR
m3sd_read_data_loop:
	ldrh	r2, [r4]		@ REG_M3SD_DIR
	strh	r2, [r0], #2
	subs	r1, r1, #2
	bne	m3sd_read_data_loop
	mov	ip, #0x08
	strh	ip, [r3]		@ REG_M3SD_STS
	mov	r0, #1			@ R0=OK
m3sd_read_data_exit:
	m3_set_ram			@ swith to RAM mode
	gba_suffix
	ldmfd   sp!,{r4-r8}		@ restore used registers
	mov	pc, lr

/*****************************************************************************/

	@ Write at minimum 8 clock cycles to the card.
	.ALIGN
	.GLOBAL m3sd_send_clocks
m3sd_send_clocks:
	stmfd   sp!,{r4-r5}		@ use additional registers
	gba_prefix
	m3_set_io			@ switch to IO mode
	@ setup pointers to the most used card registers
	ldr	r3, =REG_M3SD_STS
	ldr	r4, =REG_M3SD_DIR
	readbyte m3sd_send_clocks_exit
m3sd_send_clocks_exit:
	m3_set_ram			@ swith to RAM mode
	gba_suffix
	ldmfd   sp!,{r4-r5}		@ restore used registers
	mov	pc, lr

/*****************************************************************************/

	@ 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
	.GLOBAL m3sd_calc_crc
m3sd_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
m3sd_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     m3sd_calc_crc_loop 

	mov	r2,r9
	mov	r8,#16
m3sd_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	m3sd_calc_crc_write_data

	ldmfd	sp!,{r4-r9}
	mov	pc, lr

/*****************************************************************************/

	.END

/*****************************************************************************/

--- NEW FILE: m3sd_c.c ---
/*
 *  linux/drivers/mmc/m3sd_c.c - M3 SD driver
 *
 *  Copyright (C) 2006 Amadeus, All Rights Reserved.
 *  Based on the old non-mmc driver by by Jean-Pierre Thomasset.
 *
 * 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.
 */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
#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>
#include <asm/irq.h>
#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 */

#ifdef CONFIG_MMC_DEBUG
#define READ_CRC
#define HALT_ON_ERROR
#define DBG(x...)	printk(x)
#else
#define DBG(x...)	do { } while (0)
#endif

#ifdef HALT_ON_ERROR
#define halt() do { } while (1)
#else
#define halt() do { } while (0)
#endif

#define BLOCKSIZE 	512

#define DRIVER_NAME	"m3sd"
#define DRIVER_VERSION	"1.1.1"

/*****************************************************************************/

struct m3sd_host {
	struct mmc_host		*mmc;
	u8			inactive;
};

/*****************************************************************************/
/* 
 * Low-level assembler stuff in m3sd_s.S 
 */

/* Test if the card is present.
   Return != 0 if present. */
extern int m3sd_detect_card(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 m3sd_send_command_resp(u8 *data, int len, int reslen);

/* Wait for the DATA line to become HIGH.
   Return != 0 if OK, 0 if timeout.
   Maximum length of testing is 1ms. */
extern int m3sd_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. */
extern int m3sd_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. */
extern int m3sd_read_data(u8 *data, int len);

/* Write at minimum 8 clock cycles to the card. */
extern void m3sd_send_clocks(void);

/* 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 m3sd_calc_crc(u8 *data, int len, u8* crc);

/*****************************************************************************/
/* 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)));

/*****************************************************************************/

/* Improved CRC7 function provided by cory1492 */
inline static u8 m3sd_crc7(u8* data, int cnt)
{
    int i;
    u8 crc, temp;

    crc = 0;
    for ( ; cnt; cnt--)
    {
        temp = *data++;
        for (i = 0; i < 8; i++)
        {
            crc <<= 1;
            if ((temp & 0x80) ^ (crc & 0x80)) crc ^= 0x09;
            temp <<= 1;
        }
    }
    crc = (crc << 1) | 1; /* stop bit */
    return(crc);
} 


/* Wait until ready on the data lines */
/* return 0 if ready, 1 if busy */
inline static int m3sd_waitready(void)
{
	int i;

	for (i = 1000; i; i--) {
		if (m3sd_wait_ready())
			return 0;
	}
	return 1;
}

/* send a SD command */
/* @return 0 for success, != 0 otherwise */
static int m3sd_send_cmd(struct mmc_command *cmd)
{
	u8 *p = sd_databuf;
	u16 *p16 = (u16 *)p;
	int i;
	int reslen;

	/* stop the clock timer, we will send a command */
	del_timer(&clock_timer);

	/* Start without error */
	cmd->error = MMC_ERR_NONE;

	/* write command and arg into command buffer */
	/* write 3 x 16 bit */
	*p16++ = cmd->opcode | 0x40;
	*p16++ = cmd->arg >> 16; 
	*p16 = cmd->arg; 
	
	/* 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--) {
		int ret = m3sd_send_command_resp(sd_databuf, 6, reslen);
		if (!ret)	/* all OK */
			break;
		if (ret == 1)	/* Card busy, try again */
			continue;
		if (ret >= 2) {	/* Timeout error */
			printk(KERN_ERR "CMD:Error %d at command/response\n", ret);
			cmd->error = MMC_ERR_TIMEOUT;
			return -1;
		}
	}
	if (!i) {
		printk( KERN_ERR "CMD:Timeout before command\n");
		cmd->error = MMC_ERR_TIMEOUT;
		halt();
		return -1;
	}

	/* what type of response do we get? */
	switch (cmd->flags & MMC_RSP_MASK) {

	case MMC_RSP_NONE:		/* no response */
		break;

	case MMC_RSP_SHORT:		/* 48 bit = 6 bytes response */
	case MMC_RSP_LONG:		/* 136 bit response */

		/* Skip response, if it is a read data command.
                   Response and data may come the same time. */
		switch (cmd->opcode) {
		case MMC_READ_SINGLE_BLOCK:
		case MMC_READ_MULTIPLE_BLOCK:
		case SD_APP_SEND_SCR:
			cmd->resp[0] = 0x00000B20; /* fake response */
			return 0;
		}  

		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]  = *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++;
		}
		DBG("Got native response %X %X %X %X\n", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
		break;
	default:
		printk(KERN_ERR "Invalid flags code from mmc layer: %d\n", cmd->flags);
		cmd->error = MMC_ERR_INVALID;
		halt();
		return -1;
	}

	/* Busy command? (== STOP) */
	if (cmd->flags & MMC_RSP_BUSY) {

		/* Wait until ready on the data lines */
		if (m3sd_waitready()) {
			/* Timeout error */
			printk(KERN_ERR "Busy: timeout waiting for not busy\n");
			cmd->error = MMC_ERR_TIMEOUT;
			halt();
			return -1;
		}
	}

	/* success */
	return 0;
}

/*
 * Transfer data blocks from/to sd card.
 */
static void m3sd_xfer( struct mmc_data *data )
{
	int sgindex;
	int size = data->blocks << data->blksz_bits;
	struct scatterlist *sg = data->sg;
	int i;

     	DBG("%s Bytes=%d\n",__FUNCTION__, size);

	/* Iterate through the s/g list */
	data->bytes_xfered = 0;
	data->error = MMC_ERR_NONE;
	for (sgindex = 0; sgindex < data->sg_len; sgindex++) {
		u8 *p;
		int sglength;

		/* get the start address */
		p = (page_address(sg[sgindex].page)+sg[sgindex].offset);

		/* compute the length */
		sglength = sg[sgindex].length;
		if (size < sglength)
			sglength = size;

		/* transfer the physical sectors */
		while (sglength > 0) {
			int length = sglength;
			/* break down to sector length */
			if (length > 512)
				length = 512;
			
			/* do the transfer */
			if (data->flags & MMC_DATA_READ) {

				/* wait max. 100ms for start bit, read the data+crc+end bit */
				for( i=100; i; i--) {
					if (m3sd_read_data(sd_databuf, length+8))
						break;
				}
				if (!i) {
					/* Timeout error */
					printk(KERN_ERR "Read: timeout waiting for read data\n");
					data->error = MMC_ERR_TIMEOUT;
					halt();
					return;
				}
#ifdef READ_CRC
				/* check the CRC */
				m3sd_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();
						return;
					}
				} 
#endif
				/* copy the data */
				memcpy(p, sd_databuf, length);

			} else if (data->flags & MMC_DATA_WRITE) {

				/* copy the data */
				memcpy(sd_databuf, p, length);

				/* calculate the crc */
				m3sd_calc_crc(sd_databuf, length, &sd_databuf[length]);

				/* Wait until ready on the data lines */
				if (m3sd_waitready()) {
					/* Timeout error */
					printk(KERN_ERR "before Write: timeout waiting for ready\n");
					data->error = MMC_ERR_TIMEOUT;
					halt();
					return;
				}

				/* Write data, check CRC response */
				if (!m3sd_send_data(sd_databuf, length+8)) {
					/* Timeout error */
					printk(KERN_ERR "BAD CRC response\n");
					data->error = MMC_ERR_TIMEOUT;
					halt();
					return;
				}
			}
	
			/* ready with one physical sector */
			p += length;
			data->bytes_xfered += length;
			size -= length;
			sglength -= length;
		}

		/* stop if all done */
		if (size <= 0) break;
	}

	if (data->flags & MMC_DATA_WRITE) {
		/* Wait until ready on the data lines */
		if (m3sd_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 m3sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
	struct m3sd_host *host = mmc_priv(mmc);
	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.
	   if the hardware/the driver can only do 4bit transfers. */
	if (mmc->card_selected) {
		mmc->card_selected->scr.bus_widths |= SD_SCR_BUS_WIDTH_4;
	}

	switch (mrq->cmd->opcode){
	/* do a retry for data I/O */
	case MMC_READ_SINGLE_BLOCK:
	case MMC_READ_MULTIPLE_BLOCK:
	case MMC_WRITE_BLOCK:
	case MMC_WRITE_MULTIPLE_BLOCK:
		retry = 3;
		break;
	/* check if we have an inactivation command */
	case SD_APP_OP_COND:
	case MMC_GO_INACTIVE_STATE:
		host->inactive = 1;
		break;
	/* MMC_ALL_SEND_CID: fake a timeout for the second card */
	/* (maybe better if we know to switch CS on/off) */
	case MMC_ALL_SEND_CID:
		if (!host->inactive) {
			DBG("Fake Timeout for second SEND_CID\n");
			mrq->cmd->error = MMC_ERR_TIMEOUT;
		    	mmc_request_done(mmc, mrq);
			sd_active = 0;
			return;
		}
		break;
	}

	while (retry--) {
		/* Send the command to the card */
		mrq->cmd->error = MMC_ERR_NONE;
		ret = m3sd_send_cmd(mrq->cmd);
		if (ret) 
			continue;

		/* check if we have an activation */
		if (mrq->cmd->opcode == MMC_SET_RELATIVE_ADDR)
			host->inactive = 0;

		if ( mrq->data ) {
			mrq->data->error = MMC_ERR_NONE;
			m3sd_xfer( mrq->data );
			if (mrq->stop) {
				mrq->stop->error = MMC_ERR_NONE;
				ret = m3sd_send_cmd(mrq->stop);
				if (ret)
					continue;
			}
			if (mrq->data->error != MMC_ERR_NONE)
				continue;
		}
		break;
	}

	/* access done */
	sd_active = 0;

	/* 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 m3sd_timeout(unsigned long arg)
{
	if (sd_active)
		return;	/* nothing to do, next timeout will come */
	
	/* send 8 clocks after last command */
	m3sd_send_clocks();
}

/* read the write protect switch */
static int m3sd_get_ro(struct mmc_host *mmc)
{
	DBG("%s\n",__FUNCTION__);
	return 0;
}

/* set operating conditions for the host */
static void m3sd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
#if 0
	struct dsmemsd_host *host = mmc_priv(mmc);
    	DBG("%s\n",__FUNCTION__);

    	DBG("bus_mode    = %x\n", ios->bus_mode);
	DBG("chip_select = %x\n", ios->chip_select);
    	DBG("bus_width   = %x\n", ios->bus_width);

	DBG("m3sd_set_ios: clock %u power %u vdd %u.%01u\n",
	    ios->clock, ios->power_mode, (ios->vdd-4+17) / 10,
	    (ios->vdd-4+17) % 10);
#endif

	/* ignore power mode changes - we are always on */
	/* ignore chip select changes for now - don't know how to change */
	/* ignore clock - only one speed available */
	/* ignore vdd - only 3.3 volts available */
	/* ignore bus width - only 4 bit available */
	/* ignore bus mode - only push-pull available */
}

static struct mmc_host_ops m3sd_ops = {
 	.request	= m3sd_request,
	.get_ro		= m3sd_get_ro,
	.set_ios	= m3sd_set_ios,
};

/* setup the SD host controller */
static int m3sd_probe(struct device *dev)
{
	struct mmc_host *mmc;
	struct m3sd_host *host = NULL;
    	DBG("%s\n",__FUNCTION__);

	if (m3sd_detect_card()) {
		printk(KERN_INFO "M3 SD detected\n");
	} else {
		/* device not found */
		return -ENODEV;
	}

        /* allocate host data structures */
	mmc = mmc_alloc_host(sizeof(struct m3sd_host), dev);
	if (!mmc) {
		return -ENOMEM;
	}

	/* init timer structure */
	init_timer(&clock_timer);
	clock_timer.function = m3sd_timeout;

	/* populate host data structures */
	mmc->ops = &m3sd_ops;
	mmc->f_min = 25000000;
	mmc->f_max = 25000000;
	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
	mmc->caps = MMC_CAP_4_BIT_DATA;
	mmc->mode = MMC_MODE_SD;

	/* As we are doing transfers in software, we have no real limits.
	   So use some big numbers here. */
	mmc->max_seg_size = 0x10000;
	mmc->max_hw_segs  = 0x100;	
	mmc->max_phys_segs= 0x100;	
	mmc->max_sectors  = 0x100;	

	host = mmc_priv(mmc);
	host->mmc = mmc;

	dev_set_drvdata(dev, mmc);
	mmc_add_host(mmc);

	return 0;
}

static int m3sd_remove(struct device *dev)
{
	struct mmc_host *mmc = dev_get_drvdata(dev);
	dev_set_drvdata(dev, NULL);

	if (mmc) {
		mmc_remove_host(mmc);
		mmc_free_host(mmc);
	}
	return 0;
}

/* no power managment here */
#define m3sd_suspend	NULL
#define m3sd_resume	NULL

static void m3sd_platform_release(struct device * device){
	/* never */
}

static struct platform_device m3sd_device = {
    .name = DRIVER_NAME,
    .dev = {
        .release = m3sd_platform_release,
        }
};

static struct device_driver m3sd_driver = {
	.name		= DRIVER_NAME,
	.bus		= &platform_bus_type,
	.probe		= m3sd_probe,
	.remove		= m3sd_remove,
	.suspend	= m3sd_suspend,
	.resume		= m3sd_resume,
};

static int __init m3sd_init(void)
{
    int ret;
	ret = driver_register(&m3sd_driver);
    if (!ret) {
        ret = platform_device_register( &m3sd_device );
    }
    return ret ;
}

static void __exit m3sd_exit(void)
{
	driver_unregister(&m3sd_driver);
}

module_init(m3sd_init);
module_exit(m3sd_exit);

MODULE_DESCRIPTION("M3 SD Driver");
MODULE_LICENSE("GPL");




More information about the dslinux-commit mailing list