/*****************************************************************************************
 *
 * sdcard.c: Matthew Millman
 *
 * A driver for SD/MMC Cards attached to SPI Controllers.
 * This driver is completely incompatible with SD-Bus Hardware.
 *
 * Heavily modified version of the original file drsd_main.c, from the proprietry MT Codebase - 
 * to be a little more lightweight and more 'open-source-like'.
 *
 * It would be fair to say this driver suffers a bit of an identity crisis, although 
 * originally written as an SDCard driver, it is in effect an MMC driver as the SD part
 * of the card is never actually used. To the outside world, this driver presents its 
 * self as MMC.
 *
 * The write functionality of this code is implemented but has not been tested since it
 * was ported to U-Boot. it is very likely broken.
 *
 * Original code by Alastair Sinton, Sean Lin
 *
 *****************************************************************************************
 */

#include <common.h>
#include <diag.h>

#ifdef CONFIG_MMC_SPI
#include <spi.h>
#include <mmc_spi.h>

extern int 	fat_register_device(block_dev_desc_t *dev_desc, int part_no);

#define EPRINTF(...) printf(__VA_ARGS__)
#define DPRINTF(...) //printf(__VA_ARGS__)

#define SDCARD_INIT_SEQ_8CLOCKS				10
#define SDCARD_INIT_TIME_MAX_MS				1000
#define SDCARD_NCR_MAX_8CLOCKS				8
#define SDCARD_NWR_MIN_8CLOCKS				1
#define SDCARD_NAC_MAX_MS				100

#define SDCARD_INIT_SLEEP_US				10000
#define SDCARD_INIT_TIMEOUT_MS				SDCARD_INIT_TIME_MAX_MS

#define SDCARD_BUSYWAIT_SLEEP_US			1000
#define SDCARD_BUSYWAIT_TIMEOUT_MS			1000

#define SDCARD_RESPONSEWAIT_TIMEOUT_MS			(SDCARD_NAC_MAX_MS * 2)

#define SDCARD_TRIES_MAX				3

#define SDCARD_COMMAND_LENGTH				6
#define SDCARD_R1_RESPONSE_LENGTH			1
#define SDCARD_R2_RESPONSE_LENGTH			2
#define SDCARD_R3_RESPONSE_LENGTH			5
#define SDCARD_CSD_LENGTH				16
#define SDCARD_CID_LENGTH				16
#define SDCARD_BLOCK_LENGTH				512

#define SDCARD_CMD0_GO_IDLE_STATE			0
#define SDCARD_CMD1_SEND_OP_COND			1
#define SDCARD_CMD8_SEND_IF_COND			8
#define SDCARD_CMD9_SEND_CSD				9
#define SDCARD_CMD10_SEND_CID				10
#define SDCARD_STOP_TRANSMISSION			12
#define SDCARD_CMD13_SEND_STATUS			13
#define SDCARD_SET_BLOCKLEN				16
#define SDCARD_CMD17_READ_SINGLE_BLOCK			17
#define SDCARD_READ_MULTIPLE_BLOCK			18
#define SDCARD_CMD24_WRITE_BLOCK			24
#define SDCARD_WRITE_MULTIPLE_BLOCK			25
#define SDCARD_PROGRAM_CSD				27
#define SDCARD_SET_WRITE_PROT				28
#define SDCARD_CLR_WRITE_PROT				29
#define SDCARD_SEND_WRITE_PROT				30
#define SDCARD_ERASE_WR_BLK_START_ADDR			32
#define SDCARD_ERASE_WR_BLK_END_ADDR			33
#define SDCARD_ERASE					38
#define SDCARD_APP_CMD					55
#define SDCARD_GEN_CMD					56
#define SDCARD_CMD58_READ_OCR				58
#define SDCARD_CMD59_CRC_ON_OFF				59

#define SDCARD_APP_OP_COND				41

#define SDCARD_R1_ERRORS_MASK				0x7F
#define SDCARD_R1_PARAMETER_ERROR			0x40
#define SDCARD_R1_ADDRESS_ERROR				0x20
#define SDCARD_R1_ERASE_SEQUENCE_ERROR			0x10
#define SDCARD_R1_COMMAND_CRC_ERROR			0x08
#define SDCARD_R1_ILLEGAL_COMMAND			0x04
#define SDCARD_R1_ERASE_RESET				0x02
#define SDCARD_R1_IN_IDLE_STATE				0x01

#define SDCARD_R2_ERRORS_MASK				0xFF
#define SDCARD_R2_OUT_OF_RANGE				0x80
#define SDCARD_R2_CSD_OVERWRITE				0x80
#define SDCARD_R2_ERASE_PARAM_ERROR			0x40
#define SDCARD_R2_WRITE_PROT_VIOLATION			0x20
#define SDCARD_R2_CARD_ECC_FAILED			0x10
#define SDCARD_R2_CARD_CONTROLLER_ERROR			0x08
#define SDCARD_R2_GENERAL_ERROR				0x04
#define SDCARD_R2_WRITE_PROT_ERASE_SKIP			0x02
#define SDCARD_R2_LOCK_UNLOCK_FAILED			0x02
#define SDCARD_R2_CARD_IS_LOCKED			0x01

#define SDCARD_DATAWR_FIXED_MASK			0x11
#define SDCARD_DATAWR_FIXED_VALUE			0x01

#define SDCARD_DATAWR_STATUS_MASK			0x0E
#define SDCARD_DATAWR_STATUS_ACCEPTED			0x04
#define SDCARD_DATAWR_STATUS_CRC_ERROR			0x0A
#define SDCARD_DATAWR_STATUS_WRITE_ERROR		0x0C

#define SDCARD_DATA_START_BLOCK_VALUE			0xFE

#define SDCARD_DATARE_ERRORS_MASK			0x1F
#define SDCARD_DATARE_CARD_IS_LOCKED			0x10
#define SDCARD_DATARE_OUT_OF_RANGE			0x08
#define SDCARD_DATARE_CARD_ECC_FAILED			0x04
#define SDCARD_DATARE_CARD_CONTROLLER_ERROR		0x02
#define SDCARD_DATARE_GENERAL_ERROR			0x01

typedef struct
{
	u8 writeProtected;
	//Card register values
	u8 csd[SDCARD_CSD_LENGTH];
	u8 cid[SDCARD_CID_LENGTH];
	//Card geometry
	u32 max_block_size;				/*Maximum read data block size*/
	u32 block_count;				/*Number of max-size blocks on the card*/
	u32 max_block_shift;
	u8  version;
	u8  high_capacity;
} sdInstanceT;

static block_dev_desc_t mmccard_dev;

static sdInstanceT sd_instance;

static void	sdcard_bus_delay(void *, u32 byte_count);
static u8	sdcard_response_wait(void *, u8 * response);
static u8	sdcard_crc7_compute(const u8 * byte, u32 byte_count);
static u16	sdcard_crc16_compute(const u8 * byte, u32 byte_count);
static void	sdcard_command_build(void *, u8 * cmd_token, u32 cmd_number, u32 cmd_arg);
static void	sdcard_command_write(void *, u32 cmd_number, u32 cmd_arg);
static u8 	sdcard_command_response_read_and_check(void *, u8 * idle_state_ret);
static u8 	sdcard_data_token_read_and_check(void *, void * block, u32 count);
static u8 	sdcard_card_identify(void *);
static u8	sdcard_card_identify_and_retry(void *);
static u32	sdcard_sector_read(void *, void * sector, u32 index, u32 count);
static u32	sdcard_sector_read_and_retry(void *, void * sector, u32 index, u32 count);
#define BITS(n)	((n)*8)

/* sdcard_bus_delay()
 *
 * Emits a given number of bytes' worth of clock cycles on the SPI bus, 
 * by transmitting binary 1s for 8 * byteCountToEmit clock periods
 */
 
static void sdcard_bus_delay(void * instance, u32 byte_count)
{
	u8 dummy;
	
	DPRINTF("sdcard: sdcard_bus_delay(): byte_count=%d\n", byte_count);
	
	dummy = 0xFF;
	
	while (byte_count > 0)
	{
		spi_xfer(instance, BITS(1), &dummy, NULL, SPI_XFER_BEGIN|SPI_XFER_END);
		byte_count--;
	}

}

/* sdcard_response_wait()
 *
 * Receives from the SPI bus until a response from the SD card is received.
 * Returns the first byte of the response to the caller.
 *
 * This function may be used to wait for a command response after a command, 
 * a data response after a data block write, or a data block after a block 
 * read command.  The timeout is long because a data block may take up to 
 * 100ms to arrive after a data read command.
 */
 
static u8 sdcard_response_wait(void * instance, u8 * response)
{
	u8	response_found;
	u32	current_ms;
	u32	start_ms;
	u8	timed_out;
	u32	skips;

	skips = 0;
	timed_out = 0;
	response_found = 0;
	*response = 0xFF;	/*As if failure*/
	
	start_ms = get_timer(0);

	do
	{
		current_ms = get_timer(0);
		
		if (current_ms < start_ms)	/*Timer has wrapped around*/
		{
			start_ms = current_ms;	/*Restart our time-out*/
		}
		
		timed_out = (current_ms - start_ms > SDCARD_RESPONSEWAIT_TIMEOUT_MS);
		
		spi_xfer(instance, BITS(1), NULL, response, SPI_XFER_BEGIN|SPI_XFER_END);
    
		response_found = (*response != 0xFF);
		
		skips++;
	} 
 	while (!response_found && !timed_out);
	
	if (timed_out)
	{
		DPRINTF("sdcard: sdcard_response_wait(): timed out! skips=%u\n", skips);
		return 0;
	}
	
	DPRINTF("sdcard: sdcard_response_wait(): response=0x%02X, skips=%u\n", *response, skips);
	
	return 1;
}

static unsigned card_mb(void)
{
	unsigned mb = sd_instance.block_count;
	int i;

	/* Divide by 1e6 by multiplying by (2/5)^6 * 2^(-12) */
	/* Do the (2/5)^6 before multiplying by the block size */
	/* This ensures no overflow for up to 2^31 blocks */

	for (i = 0; i < 6; i++) {
		mb = (mb * 2 + 2) / 5;
	}
	/* Ensure result is rounded */
	mb = (mb + (1 << (11 - sd_instance.max_block_shift))) >>
	     (12 - sd_instance.max_block_shift);
	return mb;
}

/* sdcard_crc7_compute()
 *
 * Computes and returns the CRC7 (as used in MMC and SD card commands) of an 
 * array of bytes.
 *
 * The CRC's generator polynomial is x**7 + x**3 + 1.
 * Its "Williams parameters" are:
 *   Name   : ?
 *   Width  : 7
 *   Poly   : 09     //Not reflected
 *   Init   : 00
 *   RefIn  : False
 *   RefOut : False
 *   XorOut : 0000
 *   Check  : 75     //Checksum of character array '123456789'
 *
 * References:
 * 1. Ross Williams "A painless guide to CRC error detection algorithms" v3
 *    19-Aug-1993, ftp.adelaide.edu.au/pub/rocksoft/crc_v3.txt
 *    E.g. http://www.cs.waikato.ac.nz/~312/crc.txt
 * 2. Siemens MMC application note
 *
 * Arguments:
 *   bytePt   : pointer to byte array containing the data to checksum
 *   byteCount: number of bytes of data to compute the checksum over
 *
 * Returns:
 *   CRC7 of the given data
 */
 
static u8 sdcard_crc7_compute(const u8 * byte, u32 byte_count)
{
	u32 byte_index;
	u32 bit_index;
	u8  crc;

	/*	Compute and return the CRC7 of the given data
	*/
	crc = 0;

	for (byte_index = 0; byte_index < byte_count; byte_index++)
	{
		for (bit_index = 0; bit_index < 8; bit_index++)
		{
			crc <<= 1;
			if ((((byte[byte_index] << bit_index) ^ crc) & 0x80) != 0)
			{
				crc ^= 0x09;	/*Generator polynomial x**7 (implicit) + x**3 + 1*/
			}
		}
	}
	return crc & 0x7F;
}

/* sdcard_crc16_compute()
 *
 * Computes and returns the CRC16 (as used in MMC and SD card data blocks) of 
 * an array of bytes.
 *
 * The CRC's generator polynomial is x**16 + x**12 + x**5 + 1.
 * This is the CCITT-CRC16 polynomial.
 * Its "Williams parameters" are:
 *   Name   : ?
 *   Width  : 16
 *   Poly   : 1021		//Not reflected
 *   Init   : 0000
 *   RefIn  : False
 *   RefOut : False
 *   XorOut : 0000
 *   Check  : 31C3		//Checksum of character array '123456789'
 *
 * References:
 * 1. Ross Williams "A painless guide to CRC error detection algorithms" v3
 *    19-Aug-1993, ftp.adelaide.edu.au/pub/rocksoft/crc_v3.txt
 *    E.g. http://www.cs.waikato.ac.nz/~312/crc.txt
 * 2. Siemens MMC application note
 *	Arguments:
 *	  cmdTokenPt : pointer to buffer to receive the command token.  The buffer 
 *	               must have room for SDCARD_COMMAND_LENGTH bytes of data.
 *	  cmdNumber  : SD card SPI-mode command number
 *	  cmdArgument: argument value for the command, if any
 *
 *	Outputs:
 *	  none
 *
 *	Returns:
 *	  TRUE  if the command was built successfully
 *	  FALSE if the command number is unknown
 *
 * Arguments:
 *   bytePt   : pointer to byte array containing the data to checksum
 *   byteCount: number of bytes of data to compute the checksum over
 *
 * Returns:
 *   CRC16 of the given data
 */
 
static u16 sdcard_crc16_compute(const u8 * byte, u32 byte_count)
{
	u32 byte_index;
	u32 bit_index;
	u32 crc;

	/*	Compute and return the CRC16 of the given data
	*/
	crc = 0;

	for (byte_index = 0; byte_index < byte_count; byte_index++)
	{
		for (bit_index = 0; bit_index < 8; bit_index++)
		{
			crc <<= 1;
			if ((((((u32) byte[byte_index]) << (bit_index + 9)) ^ crc) & 0x10000) != 0)
			{
				crc ^= 0x1021;	/*Generator polynomial x**16 (implicit) + x**12 + x**5 + 1*/
			}
		}
	}
	
	return crc;
}

/* sdcard_command_build()
 *
 * Builds the SD card SPI-mode command token for a given SD command number
 */

static void sdcard_command_build(void * instance, u8 * cmd_token, u32 cmd_number, u32 cmd_arg)
{

  DPRINTF("sdcard: sdcard_command_build(): cmd_number=%d cmd_arg=%d\n", cmd_number, cmd_arg);

  memset(cmd_token, 0, SDCARD_COMMAND_LENGTH);
  cmd_token[0] = 0x40 | (cmd_number & 0x3F);

  /*	Create the argument value, depending on the command number
  */
	switch (cmd_number)
	{
		case SDCARD_CMD17_READ_SINGLE_BLOCK:
		case SDCARD_READ_MULTIPLE_BLOCK:
		case SDCARD_CMD24_WRITE_BLOCK:
		case SDCARD_CMD58_READ_OCR:
		case SDCARD_CMD8_SEND_IF_COND:
		case SDCARD_APP_OP_COND:
			cmd_token[1] = (cmd_arg >> 24) & 0xFF;	/*Endian-independent copy*/
			cmd_token[2] = (cmd_arg >> 16) & 0xFF;
			cmd_token[3] = (cmd_arg >>  8) & 0xFF;
			cmd_token[4] = (cmd_arg      ) & 0xFF;
			break;
			
      		case SDCARD_CMD59_CRC_ON_OFF:
			cmd_token[4] = cmd_arg & 0x01;
      			break;
			
		case SDCARD_CMD0_GO_IDLE_STATE:
		case SDCARD_CMD1_SEND_OP_COND:
		case SDCARD_CMD9_SEND_CSD:
		case SDCARD_CMD10_SEND_CID:
		case SDCARD_STOP_TRANSMISSION:
		case SDCARD_CMD13_SEND_STATUS:
		case SDCARD_APP_CMD:
			break;

		default:
			EPRINTF("sdcard: sdcard_command_build(): unsupported command: %d\n", cmd_number);
      break;
  }

  /*	Create the command CRC, left-aligned in the last byte of the command token, 
   *	with the LSB set to 1 (the idle value on SD card and SPI buses)
   */
  cmd_token[SDCARD_COMMAND_LENGTH - 1] = (sdcard_crc7_compute(cmd_token, SDCARD_COMMAND_LENGTH - 1) << 1) | 1;

  DPRINTF("sdcard: sdcard_command_build(): command built: [0]=0x%02X [1]=0x%02X [2]=0x%02X [3]=0x%02X [4]=0x%02X [5]=0x%02X\n", 
	  cmd_token[0], cmd_token[1], cmd_token[2], cmd_token[3], cmd_token[4], cmd_token[5]);
}

/* sdcard_command_write()
 *
 * Writes a given command to the SD card
 */
  
static void sdcard_command_write(void * instance, u32 cmd_number, u32 cmd_arg)
{
  	u8	cmd_token[SDCARD_COMMAND_LENGTH];
  	
	DPRINTF("sdcard: sdcard_command_write(): cmd_number=%d cmd_arg=%d\n", cmd_number, cmd_arg);
	
	sdcard_command_build(instance, cmd_token, cmd_number, cmd_arg);
	spi_xfer(instance, BITS(SDCARD_COMMAND_LENGTH), cmd_token, NULL, SPI_XFER_BEGIN|SPI_XFER_END);
}

/* sdcard_command_response_read_and_check()
 *
 * Reads an R1 command response from the SD card and checks the 
 * command status reported by the card in the response
 */

static u8 sdcard_command_response_read_and_check(void * instance, u8 * idle_state_ret)
{
	u8	response;
	
	DPRINTF("sdcard: sdcard_command_response_read_and_check(): idle_state_ret=%p\n", idle_state_ret);
	
	if (idle_state_ret != NULL)
	{
		*idle_state_ret = 0;	/*Ensure the caller's variable gets a defined value*/
	}

  /*	Wait for and read the command response type R1 from the card
  */
	if (!sdcard_response_wait(instance, &response))
		goto fail;

  /*	Interpret the command response
  */
	if ((response & ~SDCARD_R1_ERRORS_MASK) != 0)
	{
		/* We're out by some bits. Get another byte and shift until high bit is zero */
		u8 response2;
		spi_xfer(instance, BITS(1), NULL, &response2, SPI_XFER_BEGIN|SPI_XFER_END);
		while (response & 0x80) {
			response = (response << 1) | ((response2 & 0x80) ? 1 : 0);
			response2 <<= 1;
		}
	}

	if (idle_state_ret != NULL)	/*In Idle State status will be handled by our caller*/
    	{
		*idle_state_ret = ((response & SDCARD_R1_IN_IDLE_STATE) != 0);
		response &= ~SDCARD_R1_IN_IDLE_STATE;
	}

	if ((response & SDCARD_R1_COMMAND_CRC_ERROR) != 0)	/*CRC error*/
	{
		EPRINTF("sdcard: sdcard_command_response_read_and_check(): command checksum error\n");
		goto fail;
    	}
	else if ((response & SDCARD_R1_ERRORS_MASK) != 0)	/*Any other error*/
    	{
		EPRINTF("sdcard: sdcard_command_response_read_and_check(): other error. response=%d\n", response);
		goto fail;
    	}

	return 1;
fail:
	
	sdcard_bus_delay(instance, 2 * SDCARD_BLOCK_LENGTH);
	return 0;
}

/* sdcard_data_token_read_and_check()
 *
 * Reads a data token containing a given amount of data from the SD card.
 */

static u8 sdcard_data_token_read_and_check(void * instance, void * block, u32 count)
{
	u8    start;
	u8    crc_array[2];
	u16    crc;
	u16    local_crc;

	
	DPRINTF("sdcard: sdcard_data_token_read_and_check(): block=%p count=%d\n", block, count);
	
	/*  Wait for and read the first byte of response from the card.  This is either 
	 *  the start block of a data token or the entirety of a data error token.
	 */
  
	if (!sdcard_response_wait(instance, &start))
	{
		EPRINTF("sdcard: sdcard_data_token_read_and_check(): error: no response\n");
		goto fail;
	}
	
	if (start != SDCARD_DATA_START_BLOCK_VALUE)	/*Start of a data block*/
	{
		EPRINTF("sdcard: sdcard_data_token_read_and_check(): error: bad response. response=0x%02X expected 0x%02X\n",
			start, SDCARD_DATA_START_BLOCK_VALUE);
		goto fail;
	}
   
	spi_xfer(instance, BITS(count), NULL, block, SPI_XFER_BEGIN|SPI_XFER_END);
	
	spi_xfer(instance, BITS(sizeof(crc_array)), NULL, crc_array, SPI_XFER_BEGIN|SPI_XFER_END);
	
	crc = (crc_array[0] << 8) + crc_array[1];	/*Endian-independent copy*/

	local_crc = sdcard_crc16_compute(block, count);

	if (local_crc != crc)
	{
		/* Ignore CRC errors on CSD/CID */
		/* Some cards calculate it incorrectly */
		if (count == 16)
			return 1;
		EPRINTF("sdcard: sdcard_data_token_read_and_check(): crc error\n");
		goto fail;
	}
	
	return 1;
fail:
	
	sdcard_bus_delay(instance, 2 * SDCARD_BLOCK_LENGTH);
	return 0;
	
}

/* sdcard_card_identify()
 *
 * Reset, initialise, and identify the SD card in the SD card slot.
 */

static u8 sdcard_card_identify(void * instance)
{
	u32	init;
	u8	idle;
	/* For computing card size and ERTFS geometry */
	u32	exp;
	u32	mant;
	u8	success;
	u8	response;
	
	success = 1;
	
	DPRINTF("sdcard: sdcard_card_identify(): entered\n");

	sdcard_select(0);
	/* Set a slow bus clock speed suitable for identifying an unknown SD card
	 */
	spi_setclock(instance, 400000, NULL);	/*400kHz*/
	sdcard_bus_delay(instance, SDCARD_INIT_SEQ_8CLOCKS);
	sdcard_select(1);

	/*  CMD0: reset the card
	 */
	sdcard_command_write(instance, SDCARD_CMD0_GO_IDLE_STATE, 0);
	
	/* Receive and ignore the response.
	*  The first few bits of the response may come back as zeros if this is the 
	*  first response since the card was inserted, because the now is the first 
	*  opportunity the card has to enable its output buffer after it learns that 
	*  it is on an SPI bus.  Therefore don't attempt to interpret the response.
	*/
	sdcard_bus_delay(	instance, 
			 	SDCARD_NCR_MAX_8CLOCKS +	/*Max. allowed delay to response*/
				SDCARD_R1_RESPONSE_LENGTH +	/*Response*/
        			SDCARD_NCR_MAX_8CLOCKS );	/*Minimum idle period after response*/

	/* Send IF_COND to find out whether SD 2.0 */
	sd_instance.version = 1;
	sdcard_command_write(instance, SDCARD_CMD8_SEND_IF_COND, 0x1AA);
	if (!sdcard_response_wait(instance, &response)) {
		DPRINTF("sdcard: could not find responseto CMD8\n");
	} else {
		uchar scratch[4];
		spi_xfer(instance, BITS(4), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);
		DPRINTF("sdcard: got response %02X scratch = %02X%02X%02X%02X\n", response,
		        scratch[0], scratch[1], scratch[2], scratch[3]);
		if (!(response & SDCARD_R1_ILLEGAL_COMMAND) &&
		    (scratch[2] & 0x0f) == 1 &&
		    (scratch[3] == 0xAA)) {
			sd_instance.version = 2;
		}
	}
	sdcard_bus_delay(instance, SDCARD_INIT_SEQ_8CLOCKS);

	/* CMD1: initialise the card, by issuing CMD1 repeatedly until the card leaves 
	 * the in-idle state
	 */

	init = 0;
			
	do
    	{
		if (sd_instance.version == 2) {
			sdcard_command_write(instance, SDCARD_APP_CMD, 0 );
			sdcard_response_wait(instance, &response);
			sdcard_bus_delay(instance, SDCARD_NCR_MAX_8CLOCKS);
			sdcard_command_write(instance, SDCARD_APP_OP_COND, 0x40000000);
		} else {
			sdcard_command_write(instance, SDCARD_CMD1_SEND_OP_COND, 0 );
		}
		
		init++;

		success = sdcard_command_response_read_and_check(instance, &idle);
		if (success)
		{
			DPRINTF("sdcard: sdcard_card_identify(): response (idle(response)=0x%02X)\n", idle);
			sdcard_bus_delay(instance, SDCARD_NCR_MAX_8CLOCKS);
		}

		udelay(SDCARD_INIT_SLEEP_US);
	} while (	success &&
        		idle &&		/*Card is still initialising*/
        		(init <= 		/*We haven't given up waiting yet*/
         			(SDCARD_INIT_TIMEOUT_MS * 1000) / SDCARD_INIT_SLEEP_US));
	

	if (idle)
	{
		EPRINTF("sdcard: sdcard_card_identify(): card did not finish initialising soon enough!\n");
		goto fail;
	}

	/* CMD59: enable command CRC checking by the card
	 */
	
	sdcard_command_write(instance, SDCARD_CMD59_CRC_ON_OFF, 1);

	if (!sdcard_command_response_read_and_check(instance, NULL))
	{
		EPRINTF("sdcard: sdcard_card_identify(): CMD59_CRC_ON_OFF: Failed\n");
		goto fail;
	}

	sdcard_bus_delay(instance, SDCARD_NCR_MAX_8CLOCKS);

	/* CMD9: read the Card-Specific Data
  	 */
	sdcard_command_write(instance, SDCARD_CMD9_SEND_CSD, 0);
	

	if (!sdcard_command_response_read_and_check(instance, NULL))
	{
		EPRINTF("sdcard: sdcard_card_identify(): request for card specific data failed\n");
		goto fail;
	}

	if (!sdcard_data_token_read_and_check(instance, sd_instance.csd, sizeof(sd_instance.csd)))
	{
		EPRINTF("sdcard: sdcard_card_identify(): read of card specific data failed\n");	
		goto fail;
	}

	sdcard_bus_delay(instance, SDCARD_NCR_MAX_8CLOCKS);

  
	/*  CMD10: read the Card Identification
	 */
	sdcard_command_write(instance, SDCARD_CMD10_SEND_CID, 0);

	if (!sdcard_command_response_read_and_check(instance, NULL))
	{
		EPRINTF("sdcard: sdcard_card_identify(): request for card identification failed\n");
		goto fail;
	}
	
	if (!sdcard_data_token_read_and_check(instance, sd_instance.cid, sizeof(sd_instance.cid)))
	{
		EPRINTF("sdcard: sdcard_card_identify(): read of card identification failed\n");	
		goto fail;
	}
	
	sdcard_bus_delay(instance, SDCARD_NCR_MAX_8CLOCKS);
	
	sdcard_select(0);

	/*  Set the bus clock to a frequency suitable for the card
	 */
	spi_setclock(instance, CONFIG_MMC_MAX_FREQ, NULL);

	/*  Interpret the CSD and CID data
	 */
	sd_instance.max_block_shift = sd_instance.csd[5] & 0xF;	/*READ_BL_LEN, normally 1001b*/
	sd_instance.max_block_size  = 1 << sd_instance.max_block_shift;

	if ((sd_instance.csd[0] & 0xc0) == 0x40) {
		mant = (((u32)(sd_instance.csd[7] & 0x3F)) << 16) +
		       (((u32)(sd_instance.csd[8])) <<  8) +
		       (((u32)(sd_instance.csd[9]))) + 1;
		exp = 10;
		sd_instance.high_capacity = 1;
	} else {
		/*  Compute the card size, in 512-byte blocks.  Valid for SD and MM cards.
		 */
		exp = ((sd_instance.csd[ 9] & 0x03) << 1) +
		      ((sd_instance.csd[10]) >> 7) + 2;
		mant = (((u32)(sd_instance.csd[6] & 0x03)) << 10) +
		       (((u32)(sd_instance.csd[7])) <<  2) +
		       (((u32)(sd_instance.csd[8] & 0xC0)) >> 6) + 1;
		sd_instance.high_capacity = 0;
	}

	sd_instance.block_count = mant << exp;

	DPRINTF("sdcard: sdcard_card_identify(): Mfr 0x%02X, OEM 0x%02X, Product 0x%02X, Rev 0x%02X, Date %u-%u\r\n",
		sd_instance.cid[0],
		sd_instance.cid[1],
		sd_instance.cid[3],
		sd_instance.cid[8],
		sd_instance.cid[14] & 0x0F,
		((int) (sd_instance.cid[13] & 0x0F)) +
		((int) (sd_instance.cid[14] >> 4)) + 2000);
	
	DPRINTF("sdcard: sdcard_card_identify(): Serial no. %u\r\n",
		(((int) sd_instance.cid[ 9]) << 24) +
		(((int) sd_instance.cid[10]) << 16) +
		(((int) sd_instance.cid[11]) <<  8) +
		(((int) sd_instance.cid[12])      ) );

	DPRINTF("sdcard: sdcard_card_identify(): Block size %u, Card size %u blocks, %uMB\r\n",
		(int) sd_instance.max_block_size,
		(int) sd_instance.block_count,
		card_mb());

	if ((sd_instance.csd[14] & 0x30) != 0)	/*Permanent or temporary write protect enabled*/
	{					/* Valid for both SD and MM cards*/
		sd_instance.writeProtected = 1;
	}
	
	return 1;
fail:
	
		sdcard_bus_delay(instance, 2 * SDCARD_BLOCK_LENGTH);
	return 0;
}

/* sdcard_card_identify_and_retry()
 *
 * Reset, initialise, and identify the SD card in the SD card slot.
 */

static u8 sdcard_card_identify_and_retry(void * instance)
{
	u32	try;

	/* Try the card identify until it succeeds or we give up
	*/

	for (try = 0; try < SDCARD_TRIES_MAX; try++)
	{
		if (!sdcard_card_identify(instance))
		{
			DPRINTF("sdcard: sdcard_card_identify_and_retry(): attempt %u: failed\n", try);
		}
		else
		{
			DPRINTF("sdcard: sdcard_card_identify_and_retry(): attempt %u: succeeded\n", try);
			return 1;
		}
	}
	
	EPRINTF("sdcard: sdcard_card_identify_and_retry(): all attempts failed\n");

	return 0;
}

/* sdcard_sector_read()
 *
 * Reads one sector of data from the SD card
 */

static u32 sdcard_sector_read(void * instance, void * sector, u32 index, u32 count)
{
	u32	address;
	u32	done;

	DPRINTF("sdcard: sdcard_sector_read(): sector=%p index=%u count=%u\n", sector, index, count);

	/*  Compute the starting address of the sector on the card
	 */
	if (sd_instance.high_capacity)
		address = index;
	else
		address = index * SDCARD_BLOCK_LENGTH;

	/*  CMD17: read single block or
	 *  CMD18: read multiple blocks
	 */
	sdcard_command_write(instance,
	                     (count == 1) ? SDCARD_CMD17_READ_SINGLE_BLOCK :
	                                    SDCARD_READ_MULTIPLE_BLOCK,
	                     address);
	

	if (!sdcard_command_response_read_and_check(instance, NULL))
	{
		EPRINTF("sdcard: sdcard_sector_read(): sector read command failed!\n");	
		return 0;
	}

	for (done = 0; done < count; done++)
	{
		if (!sdcard_data_token_read_and_check(instance, sector, SDCARD_BLOCK_LENGTH))
		{
			EPRINTF("sdcard: sdcard_sector_read(): sector data read failed!\n");
			break;
		}
		sector += SDCARD_BLOCK_LENGTH;
	}

	if (count != 1)
	{
		sdcard_command_write(instance, SDCARD_STOP_TRANSMISSION, 0);
		// First byte is probably garbage, since the card may be
		// transferring the next sector.
		sdcard_bus_delay(instance, 1);
		if (!sdcard_command_response_read_and_check(instance, NULL))
		{
			EPRINTF("sdcard: sdcard_sector_read(): stop transmission command failed!\n");
			return done;
		}
	}

	sdcard_bus_delay(instance, SDCARD_NCR_MAX_8CLOCKS);

	return done;
}

/* sdcard_sector_read_and_retry()
 *	
 * Reads one sector of data from the SD card
 *
 * Retries the operation several times if it fails.
 */

static u32 sdcard_sector_read_and_retry(void * instance, void * sector, u32 index, u32 count)
{
	u32	try;
	u32	done = 0;

	while (count)
	{
		/* Try the sector read until it succeeds or we give up
		 */

		for (try = 0; try < SDCARD_TRIES_MAX; try++)
		{
			u32 blocks = sdcard_sector_read(instance, sector, index, count);
			if (blocks) {
				count -= blocks;
				sector += SDCARD_BLOCK_LENGTH * blocks;
				index += blocks;
				done += blocks;
				DPRINTF("sdcard: sdcard_sector_read_and_retry(): attempt %u: succeeded\n", try);
				break;
			}
			DPRINTF("sdcard: sdcard_sector_read_and_retry(): attempt %u: failed\n", try);
		}
		if (try >= SDCARD_TRIES_MAX)
		{
			EPRINTF("sdcard: sdcard_sector_read_and_retry(): all attempts failed (index=%u)\n", index);
			return done;
		}
	}
	return done;
}

/*****************************************************************************************
 *	Public functions
 *****************************************************************************************
 */

static struct spi_slave *mmc_spi_slave = NULL;

/* sdcard_block_read()
 *
 * Reads one or more blocks, called by FAT
 *
 */

unsigned long mmc_spi_block_read(int dev_num, unsigned long blknr, lbaint_t blkcnt, void *dst)
{
	unsigned long ret;

	DPRINTF("sdcard: sdcard_block_read(): dev_num=%u blknr=%lu blkcnt=%lu\n", dev_num, blknr, blkcnt);
	
	if (!sdcard_is_present())
	{
		printf("SD:    No media present\n");
		return 0;
	}
	
	if (sdcard_has_changed())
	{
		printf("SD:    Card changed since last operation, re-identifying\n");	
		mmc_spi_init(0);	
	}
	
	sdcard_select(1);
	ret = sdcard_sector_read_and_retry(mmc_spi_slave, dst, blknr, blkcnt);
	sdcard_select(0);
			
	return ret;
}

/* mmc_spi_get_dev()
 *
 * Called by FAT to get the device structure
 *
 */
 
block_dev_desc_t * mmc_spi_get_dev(int dev)
{
	return ((block_dev_desc_t *)&mmccard_dev);
}



/* mmc_spi_init()
 *
 * Initialise this driver, and register the card with the FAT filesystem
 *
 */
 
void mmc_spi_init(u8 booting)
{	
	if (booting)
	{
		mmc_spi_slave = spi_setup_slave(0, 0, CONFIG_MMC_MAX_FREQ, SPI_MODE_3);

	}
	
	memset(&sd_instance, 0, sizeof(sd_instance));
	
	/* Clear changed status */
	(void)sdcard_has_changed();

	if (sdcard_is_present())
	{	
		/* Only identify if a card is present */
		sdcard_card_identify_and_retry(mmc_spi_slave);
		
		if (booting)
		{
			printf("SD:    %u MB\n", card_mb());
		}
	}
	
	/* If the card is not present, we still need something registered against FAT */
				
	mmccard_dev.if_type = IF_TYPE_MMC;
	mmccard_dev.part_type = PART_TYPE_DOS;
	mmccard_dev.dev = 0;
	mmccard_dev.lun = 0;
	mmccard_dev.type = 0;
	mmccard_dev.blksz = sd_instance.max_block_size;
	mmccard_dev.lba = sd_instance.block_count;
	
		
	sprintf((char *)mmccard_dev.vendor, "Mfr 0x%02X, OEM 0x%02X", sd_instance.cid[0], sd_instance.cid[1]);
		
	sprintf((char *)mmccard_dev.product, "Product 0x%02X",
		sd_instance.cid[3]);
	
	sprintf((char *)mmccard_dev.revision, "Rev 0x%02X", sd_instance.cid[8]);
	
	mmccard_dev.removable = 0;
	mmccard_dev.block_read = mmc_spi_block_read;
	
	fat_register_device(&mmccard_dev, 1); /* partitions start counting with 1 */
}


/* sdcard_test_response_find()
 *
 * Finds and returns the position of the first byte of an SD card response 
 * (type R1, R1b, R2, or R3) in an array of data received from the SPI bus 
 * after transmitting a command to the SD card.
 */
 
static u8 sdcard_test_response_find( const u8 * rxDataPt, u32 byteCount, 
					u32 * responseStartIndexPt )
{
	u32 byteIndex;

/*	Search the received data array for the first byte of the SD card response
 */
	for (byteIndex = 0; byteIndex < byteCount; byteIndex++)
	{
		if (rxDataPt[byteIndex] != 0xFF)	/*Start of response found*/
		{
			break;
		}
	}

/*	Return with value and status
 */
	*responseStartIndexPt = (byteIndex < byteCount) ? byteIndex : 0;

	return (byteIndex < byteCount);
} 


/* sdcard_test_data_find()
 *
 * Finds and returns the position of the first data byte of an SD card data 
 * block in an array of data received from the SPI bus.
 */
static u8 sdcard_test_data_find( const u8 * rxDataPt, u32 byteCount, 
				    u32 * responseStartIndexPt )
{
	u32 byteIndex;

/*	Search the received data array for the first byte of the SD card data block
 */
	for (byteIndex = 0; byteIndex < byteCount; byteIndex++)
	{
		if (rxDataPt[byteIndex] == 0xFE)	/*Start of data block found*/
		{
			break;
		}
	}

/*	Return with value and status
 */
	*responseStartIndexPt = (byteIndex < byteCount) ? byteIndex + 1 : 0;
	/*First data byte is the byte after the Start Block byte*/
	return (byteIndex < byteCount);
} 

#ifdef CONFIG_DIAGNOSTICS

/* sdcard_test_slot_v2()
 *
 * Tests the SD card slot hardware
 *
 * spi_driver is explicitly passed as this is likely to be run at a time
 * where memory is not yet initialised.
 *
 */
u8 sdcard_test_slot_v2(void)
{
	u8   scratch[512];
	u8   card_present;
	u8   card_write_enabled;
	u8   card_changed;
	u32  cmd_count;
	u32  response_index;
	u32  data_index;
	u16  data_crc_received;
	u8   response_ok;
	u8   all_responses_ok;
	u8   response;


/*	Check whether SD card is present in the slot.
	*	Tell the user if the SD card is present, whether it is write-protected, and 
	*	whether it has been changed.
	*	Exit early if no SD card present.
 */
	card_present = sdcard_is_present();
	card_write_enabled = !sdcard_write_protected();
	card_changed = sdcard_has_changed();

	diag_printf("\n" );

	diag_printf("SD card is %s",
		    card_present ? "present" : "not present" );

	if (card_present)
	{
		diag_printf(" and write-%s",
			  card_write_enabled ? "enabled" : "protected" );
	}

	diag_printf(".\n" );

	if (!card_present)
	{
		return 1;
	}

	diag_printf("SD card %s been changed.\n",
	            card_changed ? "has" : "has not");
	
/*	Initialise card response checking
 */
	all_responses_ok = 1;

/*	Select slow clock speed
 */
	spi_setclock(mmc_spi_slave, 400000, NULL);		/*400kHz*/

/*	Send initialisation sequence (80 clock cycles of 1s data)
 */
	sdcard_bus_delay(mmc_spi_slave, SDCARD_INIT_SEQ_8CLOCKS);

/*	Select the SD card
 */
	sdcard_select(1);

/*	Send reset command (CMD0)
 */
	sdcard_command_write(mmc_spi_slave, SDCARD_CMD0_GO_IDLE_STATE, 0);

/*	Receive the response.
 *	If this is the first response since the card was inserted, the first few
 *	bits of response may come back as zeros.
 */
	memset( scratch, 0, sizeof( scratch ) );
	
	spi_xfer(mmc_spi_slave, BITS(12+8), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);

	diag_printf(" SD card response to CMD0  = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
			 scratch[ 0], scratch[ 1], scratch[ 2], scratch[ 3], scratch[ 4],
			 scratch[ 5], scratch[ 6], scratch[ 7], scratch[ 8], scratch[ 9],
			 scratch[10], scratch[11]);

/*	CMD0 again: reset card.
*	It's not necessary to reset the card twice.  We only do this to check that
*	the response to CMD0 is byte-aligned.
*/
	sdcard_command_write(mmc_spi_slave, SDCARD_CMD0_GO_IDLE_STATE, 0 );

	memset( scratch, 0, sizeof( scratch ) );
	
	spi_xfer(mmc_spi_slave, BITS(12+8), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);

	sdcard_test_response_find(scratch, SDCARD_NCR_MAX_8CLOCKS, &response_index );

	response_ok = ((scratch[response_index] & ~0x01) == 0) &&	/*R1*/
			(scratch[response_index+1] == 0xFF);

	all_responses_ok &= response_ok;

	diag_printf(" SD card response to CMD0  = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X  %s\n",
		 scratch[ 0], scratch[ 1], scratch[ 2], scratch[ 3], scratch[ 4],
		 scratch[ 5], scratch[ 6], scratch[ 7], scratch[ 8], scratch[ 9],
		 scratch[10], scratch[11], 
			 response_ok ? "Good" : "BAD" "\a" );

	/* Send IF_COND to find out whether SD 2.0 */
	sd_instance.version = 1;
	sdcard_command_write (mmc_spi_slave, SDCARD_CMD8_SEND_IF_COND, 0x1AA);
	if (sdcard_response_wait(mmc_spi_slave, &response))
	{
		spi_xfer(mmc_spi_slave, BITS(4), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);
		if ((response & SDCARD_R1_ILLEGAL_COMMAND) == 0 &&
		    (scratch[2] & 0x0f) == 1 &&
		    (scratch[3] == 0xAA))
		{
			sd_instance.version = 2;
		}
	}
	sdcard_bus_delay(mmc_spi_slave, SDCARD_INIT_SEQ_8CLOCKS);
/* 	CMD1: initialise the card, by issuing CMD1 repeatedly until the card leaves
* 	the in-idle state
*/

	for (cmd_count = 1; cmd_count <= 10; cmd_count++)
	{
		if (sd_instance.version == 2)
		{
			sdcard_command_write(mmc_spi_slave, SDCARD_APP_CMD, 0 );
			sdcard_response_wait(mmc_spi_slave, &response);
			sdcard_bus_delay(mmc_spi_slave, SDCARD_NCR_MAX_8CLOCKS);
			sdcard_command_write(mmc_spi_slave, SDCARD_APP_OP_COND, 0x40000000);
		} else
		{
			sdcard_command_write(mmc_spi_slave, SDCARD_CMD1_SEND_OP_COND, 0 );
		}
		memset( scratch, 0, sizeof( scratch ) );
		
		spi_xfer(mmc_spi_slave, BITS(12+8), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);
		
		sdcard_test_response_find( scratch, SDCARD_NCR_MAX_8CLOCKS, &response_index );
		
		response_ok = ((scratch[response_index] & ~0x05) == 0) &&	/*R1*/
				(scratch[response_index+1] == 0xFF);

		all_responses_ok &= response_ok;
		
		diag_printf(" SD card response to CMD1  = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X  %s\n",
			 scratch[ 0], scratch[ 1], scratch[ 2], scratch[ 3], scratch[ 4],
			 scratch[ 5], scratch[ 6], scratch[ 7], scratch[ 8], scratch[ 9],
			 scratch[10], scratch[11], 
				 response_ok ? "Good" : "BAD" "\a" );

		udelay( 100000 );	/*Delay 100ms, to give 1 second total delay, which is*/
		/* the specified maximum time for an SD card to initialise*/
		if ((scratch[response_index] & 0x01) == 0)
		{ /* Idle status is now unset */
			sdcard_bus_delay(mmc_spi_slave, SDCARD_NCR_MAX_8CLOCKS);
			break;
		}
	}

/*	Crank up the SPI bus clock speed
 */
	spi_setclock(mmc_spi_slave, CONFIG_MMC_MAX_FREQ, NULL);

/*	CMD59: enable command CRC checking by the SD card
 */
	sdcard_command_write(mmc_spi_slave, SDCARD_CMD59_CRC_ON_OFF, 1 );
	
	memset( scratch, 0, sizeof( scratch ) );
	
	spi_xfer(mmc_spi_slave, BITS(12+8), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);
	
	sdcard_test_response_find(scratch, SDCARD_NCR_MAX_8CLOCKS, &response_index );
	
	response_ok = ((scratch[response_index] & ~0x01) == 0) &&	/*R1*/
			(scratch[response_index+1] == 0xFF);
	all_responses_ok &= response_ok;

	diag_printf(" SD card response to CMD59 = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X  %s\n",
		 scratch[ 0], scratch[ 1], scratch[ 2], scratch[ 3], scratch[ 4],
		 scratch[ 5], scratch[ 6], scratch[ 7], scratch[ 8], scratch[ 9],
		 scratch[10], scratch[11], 
			 response_ok ? "Good" : "BAD" "\a" );

/*	CMD9: send card-specific data
 */
	sdcard_command_write(mmc_spi_slave, SDCARD_CMD9_SEND_CSD, 0 );
	
	memset( scratch, 0, sizeof( scratch ) );
	
	spi_xfer(mmc_spi_slave, BITS(30+8), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);
	
	sdcard_test_response_find( scratch, SDCARD_NCR_MAX_8CLOCKS, &response_index );
	
	sdcard_test_data_find( &scratch[response_index + 1], SDCARD_NCR_MAX_8CLOCKS, &data_index );
	
	data_index += response_index + 1;
	
	data_crc_received = ((u16) scratch[data_index + SDCARD_CSD_LENGTH] << 8)| 
			scratch[data_index + SDCARD_CSD_LENGTH + 1];
	
	response_ok =  ((scratch[response_index] & ~0x01) == 0);		/*R1*/
	
	/* Some cards include the data token in the checksum */
	if (sdcard_crc16_compute(&scratch[data_index], SDCARD_CSD_LENGTH) != data_crc_received &&
	    sdcard_crc16_compute(&scratch[data_index-1], SDCARD_CSD_LENGTH + 1) != data_crc_received)
	{
		response_ok = 0;
	}

	all_responses_ok &= response_ok;

	diag_printf(" SD card response to CMD9  = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
		 scratch[ 0], scratch[ 1], scratch[ 2], scratch[ 3], scratch[ 4],
		 scratch[ 5], scratch[ 6], scratch[ 7], scratch[ 8], scratch[ 9],
		 scratch[10], scratch[11] );
	
	diag_printf("                             %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X  %s\n",
		 scratch[12], scratch[13], scratch[14], scratch[15], scratch[16],
		 scratch[17], scratch[18], scratch[19], scratch[20], scratch[21],
		 scratch[22], scratch[23],
		 response_ok ? "Good" : "BAD" "\a" );
/*	CMD10: send card identification
 */
	sdcard_command_write(mmc_spi_slave, SDCARD_CMD10_SEND_CID, 0 );
	memset( scratch, 0, sizeof( scratch ) );
	
	spi_xfer(mmc_spi_slave, BITS(30+8), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);
	
	sdcard_test_response_find(scratch, SDCARD_NCR_MAX_8CLOCKS, &response_index );
	
	sdcard_test_data_find(&scratch[response_index + 1], SDCARD_NCR_MAX_8CLOCKS, &data_index );
	
	data_index += response_index + 1;
	
	data_crc_received = ((u16) scratch[data_index + SDCARD_CSD_LENGTH] << 8)| 
			scratch[data_index + SDCARD_CSD_LENGTH + 1];
	
	response_ok =  ((scratch[response_index] & ~0x01) == 0);		/*R1*/
	
	if (sdcard_crc16_compute(&scratch[data_index], SDCARD_CID_LENGTH) != data_crc_received &&
	    sdcard_crc16_compute(&scratch[data_index-1], SDCARD_CID_LENGTH + 1) != data_crc_received)
	{
		response_ok = 0;
	}

	all_responses_ok &= response_ok;
	
	diag_printf(" SD card response to CMD10 = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
		 scratch[ 0], scratch[ 1], scratch[ 2], scratch[ 3], scratch[ 4],
		 scratch[ 5], scratch[ 6], scratch[ 7], scratch[ 8], scratch[ 9],
		 scratch[10], scratch[11] );
	
	diag_printf("                             %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X  %s\n",
		    scratch[12], scratch[13], scratch[14], scratch[15], scratch[16],
		    scratch[17], scratch[18], scratch[19], scratch[20], scratch[21],
		    scratch[22], scratch[23],
		    response_ok ? "Good" : "BAD" "\a" );

/*	CMD13: send status register
 */
	sdcard_command_write(mmc_spi_slave, SDCARD_CMD13_SEND_STATUS, 0);
	
	memset( scratch, 0, sizeof( scratch ) );
	
	spi_xfer(mmc_spi_slave, BITS(12+8), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);
	
	sdcard_test_response_find( scratch, SDCARD_NCR_MAX_8CLOCKS, &response_index );
	
	response_ok = ((scratch[response_index] & ~0x01) == 0) &&
			(scratch[response_index+1] == 0) &&			/*R2*/
			(scratch[response_index+2] == 0xFF);

	all_responses_ok &= response_ok;

	diag_printf(" SD card response to CMD13 = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X  %s\n",
		 scratch[ 0], scratch[ 1], scratch[ 2], scratch[ 3], scratch[ 4],
		 scratch[ 5], scratch[ 6], scratch[ 7], scratch[ 8], scratch[ 9],
		 scratch[10], scratch[11], 
			 response_ok ? "Good" : "BAD" "\a" );

/*	CMD58: read OCR register
 */
	sdcard_command_write(mmc_spi_slave, SDCARD_CMD58_READ_OCR, 0 );
	
	memset( scratch, 0, sizeof( scratch ) );
	
	spi_xfer(mmc_spi_slave, BITS(12+8), NULL, scratch, SPI_XFER_BEGIN|SPI_XFER_END);
	
	sdcard_test_response_find( scratch, SDCARD_NCR_MAX_8CLOCKS, &response_index );
	
	response_ok = ((scratch[response_index] & ~0x01) == 0) &&	/*R1 (part of R3)*/
			(scratch[response_index+5] == 0xFF);

	all_responses_ok &= response_ok;

	diag_printf(" SD card response to CMD58 = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X  %s\n",
		 scratch[ 0], scratch[ 1], scratch[ 2], scratch[ 3], scratch[ 4],
		 scratch[ 5], scratch[ 6], scratch[ 7], scratch[ 8], scratch[ 9],
		 scratch[10], scratch[11], 
			 response_ok ? "Good" : "BAD" "\a" );

/*	Deselect the SD card
 */
	sdcard_select(0);

/*	Display overall result of card response checks
 */
	diag_printf("\n" );


	diag_printf("%s\n",
	                 all_responses_ok ? "All SD card responses are good." : 
					 "Some SD card responses are bad!" );

	return 1;
}

#endif

#endif /* CONFIG_SPI_MMC */
