/*
 * sd card
 */

#include <mcf5475.h>

#define	dspi_dtar0	0x0c
#define	dspi_dsr	0x2c	
#define	dspi_dtfr	0x34	
#define	dspi_drfr	0x38
#define	time1us		1320

extern void wait_10ms(void);


void sd_com(void)		// byt senden und holen ---------------------
{

	asm
	{

		move.l		d4,dspi_dtfr(a0)
wait_auf_complett:
		btst.b		#7,dspi_dsr(a0)
		beq			wait_auf_complett
		move.l		dspi_drfr(a0),d5
		mov3q.l		#-1,dspi_dsr(a0)		// clr status register
	}
}

void sd_get_status(void)	// status holen -------------------------------
{
	asm
	{
sd_get_status:
		move.b		#0xff,d4
		bsr			sd_com
		cmp.b		#0xff,d5
		beq			sd_get_status
	}
}

void sd_rcv_info(void)	 // daten holen ----------------------------
{
	asm
	{
		moveq		#18,d3						// 16 byts + 2 byts crc
		move.b		#0xff,d4
sd_rcv_rb_w:		
		bsr			sd_get_status 
		cmp.b		#0xfe,d5				// daten bereit?
		bne			sd_rcv_rb_w				// nein->
sd_rcv_rd_rb:
		bsr			sd_com
		move.b		d5,(a2)+
		subq.l		#1,d3
		bne			sd_rcv_rd_rb
	}
}

void sd_card_idle(void)
{

	asm
	{
// sd idle
// speed =400kHz
		move.l		#0x082000ff,d4			// tx vorbesetzen
		lea			MCF_DSPI_DMCR,a0
		move.l		#0x38558897,d0				
		move.l		d0,dspi_dtar0(a0)		// 400kHz 

		move.b		#0xff,d4
		bsr			sd_com					// clocks 
		move.b		#0x40,d4				// cmd idle
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#0x95,d4
		bsr			sd_com
	}
}

int sd_card_init(void)
{

		long		az_sectors;

	asm
	{
		lea			MCF_PSC0_PSCTB_8BIT,a1
		move.l  	#'SD-C',(a1)
		move.l  	#'ard ',(a1)

		move.l		buffer,a5					// basis addresse (diesen bereich brauchen wir nicht mehr!)
		move.l		#0x1fffffff,d0				// normal dspi
		move.l		d0,MCF_PAD_PAR_DSPI
		lea			MCF_DSPI_DMCR,a0
		move.l		#0x802d3c00,(a0)			// 8 bit cs off clear fifo
		move.l		#0x38558897,d0				
		move.l		d0,dspi_dtar0(a0)			// 400kHz 
		move.l		#0x082000ff,d4				// tx vorbesetzen
		move.l		d4,dspi_dtfr				// und setzen
		mov3q.l		#-1,dspi_dsr(a0)			// status register l�schen
		
		move.l		#0xc00d3c00,(a0)			// clock on cs ist on
		bsr			wait_10ms
		move.l		#0x802d3c00,(a0)			// clock off cs off
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com
		move.l		#0x800d3c00,(a0)			// cs on
		bsr			sd_com						
		bsr			sd_com
		move.l		#0x802d3c00,(a0)			// cs off
		bsr			sd_com
		bsr			sd_com
		bsr			wait_10ms

// sd idle
		move.l		#100,d6						// 100 versuche
		move.l		#10,d3						// 10 versuche
sd_idle:
		bsr			sd_card_idle

		move.l		#10,d7
		move.b		#0xff,d4
sd_idle_leeren:
		bsr			sd_com
		cmp.b		#0x01,d5
		beq			idle_end
		subq.l		#1,d7
		bne			sd_idle_leeren
		subq.l		#1,d6
		beq			sd_not
		bra			sd_idle
idle_end:

// cdm 8
read_ic:
		move.b		#0xff,d4			// clocks 
		bsr			sd_com
		move.b		#0x48,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#0x01,d4
		bsr			sd_com
		move.b		#0xaa,d4
		bsr			sd_com
		move.b		#0x87,d4
		bsr			sd_com
		
		bsr			sd_get_status
		cmp.b		#5,d5
		beq			sd_v1
		cmp.b		#1,d5
		bne			read_ic
		
		bsr			sd_com			// 4byts zum wegwerfen
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com
		cmp.b		#0xaa,d5		// pattern zur�ckgekommen?
		bne			sd_testd3		// nein ->

		move.l		#'SDHC',(a1)
		move.b		#' ',(a1)
sd_v1:
		
// cdm 58
read_ocr:
		move.b		#0xff,d4			// clocks 
		bsr			sd_com
		move.b		#0x7a,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#0x00,d4
		bsr			sd_com
		move.b		#0x00,d4
		bsr			sd_com
		move.b		#0x01,d4
		bsr			sd_com
		
		bsr			sd_get_status
		move.l		#'Ver1',d6
		cmp.b		#5,d5
		beq			read_ocr
		cmp.b		#1,d5
		bne			read_ocr
		
		bsr			sd_com				// 4 byts zum wegwerfen
		bsr			sd_com
		bsr			sd_com
		bsr			sd_com

// acdm 41
		move.l		#20000,d6			// 20000 versuche ready can bis 1 sec gehen
wait_of_aktiv:
		move.b		#0xff,d4			// clocks 
		bsr			sd_com
		move.b		#0x77,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#0x95,d4
		bsr			sd_com

		bsr			sd_get_status
		cmp.b		#0x05,d5
		beq			wait_of_aktiv

wait_of_aktiv2:
		move.b		#0xff,d4			// clocks 
		bsr			sd_com
		move.b		#0x69,d4
		bsr			sd_com
		move.b		#0x40,d4
		bsr			sd_com
		move.b		#0x00,d4
		bsr			sd_com
		move.b		#0x00,d4
		bsr			sd_com
		move.b		#0x00,d4
		bsr			sd_com
		move.b		#0x95,d4
		bsr			sd_com

		bsr			sd_get_status
		tst.b		d5
		beq			sd_init_ok
		cmp.b		#0x05,d5
		beq			wait_of_aktiv2	
		subq.l		#1,d6
		bne			wait_of_aktiv
sd_testd3:
		subq.l		#1,d3
		bne			sd_idle
		bra			sd_error

sd_init_ok:
// fullspeed 
		move.l		#0x38551120,d0				// 22Mbit/sec
		move.l		d0,dspi_dtar0(a0)			// setzen 

// cdm 10
read_cid:
		move.b		#0xff,d4			// clocks 
		bsr			sd_com
		move.b		#0x4a,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#0x00,d4
		bsr			sd_com
		move.b		#0x00,d4
		bsr			sd_com
		move.b		#0x95,d4
		bsr			sd_com
		
		move.l		a5,a2				// adresse setzen
		bsr			sd_rcv_info

// name ausgeben
		lea			1(a5),a2
		moveq		#7,d7
sd_nam_loop:
		move.b		(a2)+,(a1)
		subq.l		#1,d7
		bne			sd_nam_loop
		move.b		#' ',(a1)

// cdm 9
read_csd:
		move.b		#0xff,d4			// clocks 
		bsr			sd_com
		move.b		#0x49,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#00,d4
		bsr			sd_com
		move.b		#0x00,d4
		bsr			sd_com
		move.b		#0x00,d4
		bsr			sd_com
		move.b		#0x01,d4
		bsr			sd_com
		
		move.l		a5,a2				// adresse setzen
		bsr			sd_rcv_info

		mvz.b		(a5),d0
		lsr.l		#6,d0
		
		bne			sd_csd2				// format v2
		move.l		6(a5),d1
		moveq		#14,d0				// bit 73..62 c_size
		lsr.l		d0,d1				// bits extrahieren
		and.l		#0xfff,d1			// 12 bits
		addq.l		#1,d1
		mvz.w		9(a5),d0
		lsr.l		#7,d0				// bits 49..47
		and.l		#0x7,d0				// 3 bits
		moveq.l		#8,d2				// x256 (dif v1 v2)
		sub.l		d0,d2		
		lsr.l		d2,d1
		bra			sd_print_size
sd_csd2:
		mvz.w		8(a5),d1
		addq.l		#1,d1
sd_print_size:
		swap		d1
		move.l		d1,d3
		lsr.l		#6,d3				//x65636 /64 -> anzahl sectors
		move.l		d3,az_sectors
		lsl.l		#1,d1
		bcc			sd_16G
		move.l		#'32GB',(a1)
		bra			sd_ok
sd_16G:
		lsl.l		#1,d1
		bcc			sd_8G
		move.l		#'16GB',(a1)
		bra			sd_ok
sd_8G:
		lsl.l		#1,d1
		bcc			sd_4G
		move.l		#' 8GB',(a1)
		bra			sd_ok
sd_4G:
		lsl.l		#1,d1
		bcc			sd_2G
		move.l		#' 4GB',(a1)
		bra			sd_ok
sd_2G:
		lsl.l		#1,d1
		bcc			sd_1G
		move.l		#' 2GB',(a1)
		bra			sd_ok
sd_1G:
		lsl.l		#1,d1
		bcc			sd_512M
		move.l		#' 1GB',(a1)
		bra			sd_ok
sd_512M:
		lsl.l		#1,d1
		bcc			sd_256M
		move.b		#'5',(a1)
		move.l		#'12MB',(a1)
		bra			sd_ok
sd_256M:
		lsl.l		#1,d1
		bcc			sd_128M
		move.b		#'2',(a1)
		move.l		#'56MB',(a1)
		bra			sd_ok
sd_128M:
		lsl.l		#1,d1
		bcc			sd_64M
		move.b		#'1',(a1)
		move.l		#'28MB',(a1)
		bra			sd_ok
sd_64M:
		lsl.l		#1,d1
		bcc			sd_32M
		move.l		#'64MB',(a1)
		bra			sd_ok
sd_32M:
		lsl.l		#1,d1
		bcc			sd_16M
		move.l		#'32MB',(a1)
		bra			sd_ok
sd_16M:
		lsl.l		#1,d1
		bcc			sd_8M
		move.l		#'16MB',(a1)
		bra			sd_ok
sd_8M:
		move.l		#'<9MB',(a1)
sd_ok:		
		move.l  	#' OK!',(a1)
		move.l		#0x0a0d,(a1)
		bra			sd_c_ok
// subs ende -------------------------------
sd_error:
		move.l  	#'Erro',(a1)
		move.l  	#'r!',(a1)
		move.l		#0x0a0d,(a1)
		bra			sd_c_error
sd_not:
		move.l  	#'non!',(a1)
		move.l		#0x0a0d,(a1)
		bra			sd_c_not
buffer:	dc.l		0,0,0,0,0,0,0,0
	}
sd_c_ok:
		return		az_sectors;
sd_c_not:
		return		-2;
sd_c_error:
		return		-1;
}

void sd_rcv_sector(void)	 // 1 sector daten holen ----------------------------
{
	if (sd_get_status() == 0xfe)
	{
		for (i = 0; i < 512; i++)
	}
	}
	asm
	{
		bsr			sd_get_status 
		cmp.b		#0xfe,d5				// daten bereit?
		bne			sd_rs_end				// nein-> error
		move.l		#512,d3					// sonst 512 byts abholen
sd_rs_loop:
		bsr			sd_com
		move.b		d5,(a2)+
		subq.l		#1,d3
		bne			sd_rs_loop
// crc holen
		bsr			sd_com
		bsr			sd_com
		clr.l		d5						// alles ok
sd_rs_end:
	}
}

int sd_card_sector_read(long sec_nr,long buf_adr)
{
		int			status ;
	asm
	{
		lea			MCF_DSPI_DMCR,a0
		move.l		#0x082000ff,d4				// tx vorbesetzen

		move.l		sec_nr,d0
		move.l		buf_adr,a2

		lsl.l		#8,d0
		add.l		d0,d0						// x 512 !
		move.l		d0,d1						// byts kehren
		swap		d1
		move.l		d1,d2
		lsr.l		#8,d1
		
		move.b		#0xff,d4			// clocks 
		bsr			sd_com
		
		move.b		#0x51,d4
		bsr			sd_com
		move.b		d1,d4
		bsr			sd_com
		move.b		d2,d4
		bsr			sd_com
		move.l		d0,d2
		lsr.l		#8,d2
		move.b		d2,d4
		bsr			sd_com
		move.b		d0,d4
		bsr			sd_com
		move.b		#0x01,d4
		bsr			sd_com

		clr.l		d5					// alles auf no error
		clr.l		status
		
		bsr			sd_get_status		// status holen
		tst.b		d5
		bne			sd_csr_end			// wenn nicht ok -> weg
// sector holen
		bsr			sd_rcv_sector
sd_csr_end:
		tst.b		d5
		beq			sd_csr_ok
		neg.l		d5					// wenn nicht ok status auf negativ
		move.l		d5,status
sd_csr_ok:
	}
	return	status;
}

void sd_send_sector(void)	 // 1 sector daten senden ----------------------------
{
	asm
	{
		move.l		#512,d3		
		move.b		#0xfe,d4			// start token
		bsr			sd_com				// senden
sd_send_wr_wb:
		move.b		(a2)+,d4			// data
		bsr			sd_com				// senden
		subq.l		#1,d3
		bne			sd_send_wr_wb	
// send crc
		move.b		#1,d4			
		bsr			sd_com				// crc 1.byt
		move.b		#1,d4			
		bsr			sd_com				// crc 2.byt
sd_send_wr_ww:
		bsr			sd_get_status
		and.l		#0x1f,d5
		clr.l		d6					//status auf OK
		cmp.b		#5,d5				//data accepted?
		beq			sd_send_end			//ja ->
		move.l		d5,d6				//sonst status sichern
sd_send_end:
		bsr			sd_com
		tst.b		d5					// warte auf geschrieben
		beq			sd_send_end
		move.l		d6,d5				// status zur�ck
	}
}

int sd_card_sector_write(long sec_nr,long buf_adr)
{
		int			status;
	asm
	{
		lea			MCF_DSPI_DMCR,a0
		move.l		#0x082000ff,d4				// tx vorbesetzen

		move.l		sec_nr,d0
		move.l		buf_adr,a2

		lsl.l		#8,d0
		add.l		d0,d0						// x 512 !
		move.l		d0,d1						// byts kehren
		swap		d1
		move.l		d1,d2
		lsr.l		#8,d1
		
		move.b		#0xff,d4			// clocks 
		bsr			sd_com
		move.b		#0x58,d4
		bsr			sd_com
		move.b		d1,d4
		bsr			sd_com
		move.b		d2,d4
		bsr			sd_com
		move.l		d0,d2
		lsr.l		#8,d2
		move.b		d2,d4
		bsr			sd_com
		move.b		d0,d4
		bsr			sd_com
		move.b		#0x01,d4
		bsr			sd_com

		clr.l		d5					// alles auf no error
		clr.l		status
		bsr			sd_get_status		// status holen
		tst.b		d5
		bne			sd_csw_end			// wenn nicht ok -> weg
// sector schreiben
		bsr			sd_send_sector
sd_csw_end:
		tst.b		d5
		beq			sd_csw_ok
		neg.l		d5					// wenn nicht ok status auf negativ
		move.l		d5,status
sd_csw_ok:
	}
	return	status;
}
