/*
 * Copyright (c) 2006, Technologic Systems.
 * All rights reserved.
 */

#ifndef _SDCORE_H_
#define _SDCORE_H_

/* Register offset definitions.  TS-SDCORE is 4 8-bit regs total. */
#define SDCMD		0
#define SDDAT		1
#define SDSTATE		2
#define SDCTRL		3

struct sdcore {
	/* virtual address of SD block register start, to be filled in
	 * by client code before calling any sdcore functions.
	 */
	unsigned int sd_regstart; 

	/* public bits for sd_state bitfield, can be read from client code.
	 * Do not write!  Other bits are used internally.
	 */
	#define SDDAT_RX	(1<<0)
	#define SDDAT_TX	(1<<1)
	#define SDCMD_RX	(1<<2)
	#define SDCMD_TX	(1<<3)
	unsigned int sd_state; 

	/* Erase hint for subsequent sdwrite() call, used to optimize 
	 * write throughput on multi-sector writes by pre-erasing this
	 * many sectors.
	 */
	unsigned int sd_erasehint;

	/* Following this comment are function pointer declarations to 
	 * OS helper functions.  The 'os_arg' member is passed as the 
	 * first argument to the helpers and should be set by
	 * client code before issueing sdreset()
	 *
	 * os_dmastream(os_arg, buf, buflen)
	 * This function should look at sd_state and set up and run an
	 * appropriate DMA transfer.  If buf is NULL, callee doesn't care 
	 * about the actual data sent/received and helper function 
	 * can do whatever it wants.  Should return 0 when DMA transfer was 
	 * run and completed successfully.  If this function pointer is
	 * NULL, PIO methods of transfer will be used instead of DMA.
	 *
	 * os_dmaprep(os_arg, buf, buflen)
	 * This function is used to prepare an area of memory for a possible 
	 * DMA transfer.  This function is called once per distinct buffer
	 * passed in.  After this function is called, os_dmastream() may be
	 * called one or more times (for sequential addresses) on subregions
	 * of the address range passed here.  Should write-back or invalidate 
	 * L1 cache lines and possibly look up physical addresses for buf 
	 * passed in if I/O buffers.  If 'os_dmaprep' is set to NULL, function
	 * call will not happen. (though os_dmastream() calls may still)
	 *
	 * os_delay(os_arg, microseconds)
	 * This function is supposed to delay or stall the processor for
	 * the passed in value number of microseconds.
	 */
	void *os_arg;
	int (*os_dmastream)(void *, unsigned char *, unsigned int);
	int (*os_dmaprep)(void *, unsigned char *, unsigned int);
	void (*os_delay)(void *, unsigned int);

	/* If the SD card last successfully reset is write protected, this
	 * member will be non-zero.
	 */
	unsigned int sd_wprot;

	/* If this card may have been already initialized by TS-SDBOOT, place
	 * the magic token it placed in the EP93xx SYSCON ScratchReg1 here
	 * to avoid re-initialization.
	 */
	unsigned int sdboot_token;

	/* The rest of these members are for private internal use and should
	 * not be of interest to client code.
	 */
	unsigned int reserved[55];
};

/* For sdreadv() / sdwritev() multi-buffer reads/writes */
struct sdiov {
	unsigned char *sdiov_base;
	unsigned int sdiov_nsect;
};


/* sdreset() should be called before sdread() or sdwrite().  It returns
 * the size in 512-byte sectors if a card was successfully detected and
 * initialized.  It will return 0 on error.  Certain public members of
 * the struct sdcore passed in should already be set.
 */
int sdreset(struct sdcore *);

/* sdread(sdcore, startsector, buf, numsectors)
 * Reads 'numsectors' of SD flash into 'buf' starting at sector 'startsector'.
 * On failure non-zero is returned.  (return val 0 means everything is ok)
 */
int sdread(struct sdcore *, unsigned int, unsigned char *, int);

/* sdwrite(sdcore, startsector, buf, numsectors)
 * Writes 'numsectors' from 'buf' starting at 'startsector'.  Returns 0 on
 * success.  If 'sdcore->sd_erasehint' is non-zero, the SD controller
 * will pre-erase that many sectors on write and then reset it back to 0.
 */
int sdwrite(struct sdcore *, unsigned int, unsigned char *, int);

/* sdreadv(sdcore, startsector, sdiov_array, arraylen
 * This is just like sdread, but with scatter/gather buffers.
 */
int sdreadv(struct sdcore *, unsigned int, struct sdiov *, int);

/* sdwritev(sdcore, startsector, sdiov_array, arraylen
 * This is just like sdwrite, but with scatter/gather buffers.
 */
int sdwritev(struct sdcore *, unsigned int, struct sdiov *, int);

/* sdsetwprot(sdcore, permanent)
 * Temporarily or permanently sets the write protect bit on the SD card.
 * If 'permanent' is non-zero, the card becomes frozen forever.
 */
int sdsetwprot(struct sdcore *, unsigned int);

#endif
