Home | History | Annotate | Line # | Download | only in boot2440
s3csdi.c revision 1.3.14.1
      1       1.1  nisimura /*-
      2       1.1  nisimura  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      3       1.1  nisimura  * All rights reserved.
      4       1.1  nisimura  *
      5       1.1  nisimura  * This code is derived from software contributed to The NetBSD Foundation
      6       1.1  nisimura  * by Paul Fleischer <paul (at) xpg.dk>
      7       1.1  nisimura  *
      8       1.1  nisimura  * Redistribution and use in source and binary forms, with or without
      9       1.1  nisimura  * modification, are permitted provided that the following conditions
     10       1.1  nisimura  * are met:
     11       1.1  nisimura  * 1. Redistributions of source code must retain the above copyright
     12       1.1  nisimura  *    notice, this list of conditions and the following disclaimer.
     13       1.1  nisimura  * 2. Redistributions in binary form must reproduce the above copyright
     14       1.1  nisimura  *    notice, this list of conditions and the following disclaimer in the
     15       1.1  nisimura  *    documentation and/or other materials provided with the distribution.
     16       1.1  nisimura  *
     17       1.1  nisimura  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     18       1.1  nisimura  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19       1.1  nisimura  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20       1.1  nisimura  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     21       1.1  nisimura  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22       1.1  nisimura  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23       1.1  nisimura  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24       1.1  nisimura  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25       1.1  nisimura  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26       1.1  nisimura  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27       1.1  nisimura  * POSSIBILITY OF SUCH DAMAGE.
     28       1.1  nisimura  */
     29       1.1  nisimura #include "s3csdi.h"
     30       1.1  nisimura 
     31       1.1  nisimura #include <arm/s3c2xx0/s3c2440reg.h>
     32       1.1  nisimura 
     33       1.1  nisimura #include <lib/libsa/stand.h>
     34       1.1  nisimura 
     35       1.2      matt #include <machine/int_mwgwtypes.h>
     36       1.1  nisimura #include <machine/limits.h>
     37       1.1  nisimura 
     38       1.1  nisimura #include <dev/sdmmc/sdmmcreg.h>
     39       1.1  nisimura 
     40       1.1  nisimura #define SDI_REG(reg) (*(volatile uint32_t*)(S3C2440_SDI_BASE+reg))
     41       1.1  nisimura 
     42       1.1  nisimura //#define SSSDI_DEBUG
     43       1.1  nisimura #ifdef SSSDI_DEBUG
     44       1.1  nisimura #define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0)
     45       1.1  nisimura #else
     46       1.1  nisimura #define DPRINTF(s) do {} while (/*CONSTCOND*/0)
     47       1.1  nisimura #endif
     48       1.1  nisimura 
     49       1.1  nisimura struct s3csdi_softc {
     50       1.1  nisimura 	int width;
     51       1.1  nisimura };
     52       1.1  nisimura 
     53       1.1  nisimura extern int pclk;
     54       1.1  nisimura 
     55       1.1  nisimura static void sssdi_perform_pio_read(struct sdmmc_command *cmd);
     56       1.1  nisimura //static void sssdi_perform_pio_write(struct sdmmc_command *cmd);
     57       1.1  nisimura 
     58       1.1  nisimura static struct s3csdi_softc s3csdi_softc;
     59       1.1  nisimura 
     60       1.1  nisimura int
     61       1.1  nisimura s3csd_match(unsigned int tag)
     62       1.1  nisimura {
     63       1.1  nisimura 	printf("Found S3C2440 SD/MMC\n");
     64       1.1  nisimura 	return 1;
     65       1.1  nisimura }
     66       1.1  nisimura 
     67       1.1  nisimura void*
     68       1.1  nisimura s3csd_init(unsigned int tag, uint32_t *caps)
     69       1.1  nisimura {
     70       1.1  nisimura 	uint32_t data;
     71       1.1  nisimura 
     72       1.1  nisimura 	*caps = SMC_CAPS_4BIT_MODE;
     73       1.1  nisimura 
     74       1.1  nisimura 	DPRINTF(("CLKCON: 0x%X\n", *(volatile uint32_t*)(S3C2440_CLKMAN_BASE + CLKMAN_CLKCON)));
     75       1.1  nisimura 
     76       1.1  nisimura 	DPRINTF(("SDI_INT_MASK: 0x%X\n", SDI_REG(SDI_INT_MASK)));
     77       1.1  nisimura 
     78       1.1  nisimura 	SDI_REG(SDI_INT_MASK) = 0x0;
     79       1.1  nisimura 	SDI_REG(SDI_DTIMER) = 0x007FFFFF;
     80       1.1  nisimura 
     81       1.1  nisimura 	SDI_REG(SDI_CON) &= ~SDICON_ENCLK;
     82       1.1  nisimura 
     83       1.1  nisimura 	SDI_REG(SDI_CON) = SDICON_SD_RESET | SDICON_CTYP_SD;
     84       1.1  nisimura 
     85       1.1  nisimura 	/* Set GPG8 to input such that we can check if there is a card present
     86       1.1  nisimura 	 */
     87       1.1  nisimura 	data = *(volatile uint32_t*)(S3C2440_GPIO_BASE+GPIO_PGCON);
     88       1.1  nisimura 	data = GPIO_SET_FUNC(data, 8, 0x00);
     89       1.1  nisimura 	*(volatile uint32_t*)(S3C2440_GPIO_BASE+GPIO_PGCON) = data;
     90       1.1  nisimura 
     91       1.1  nisimura 	/* Check if a card is present */
     92       1.1  nisimura 	data = *(volatile uint32_t*)(S3C2440_GPIO_BASE+GPIO_PGDAT);
     93  1.3.14.1     skrll 	if ( (data & (1<<8)) == (1<<8)) {
     94       1.1  nisimura 		printf("No card detected\n");
     95       1.1  nisimura 		/* Pin 8 is low when no card is inserted */
     96       1.1  nisimura 		return 0;
     97       1.1  nisimura 	}
     98       1.1  nisimura 	printf("Card detected\n");
     99       1.1  nisimura 
    100       1.1  nisimura 	s3csdi_softc.width = 1;
    101       1.1  nisimura 
    102       1.1  nisimura 	/* We have no private data to return, but 0 signals error */
    103       1.1  nisimura 	return (void*)0x01;
    104       1.1  nisimura }
    105       1.1  nisimura 
    106       1.1  nisimura int
    107       1.1  nisimura s3csd_bus_clock(void *priv, int freq)
    108       1.1  nisimura {
    109       1.1  nisimura 	int div;
    110       1.1  nisimura 	int clock_set = 0;
    111       1.1  nisimura 	int control;
    112       1.1  nisimura 	int clk = pclk/1000; /*Peripheral bus clock in KHz*/
    113       1.1  nisimura 
    114       1.1  nisimura 	/* Round peripheral bus clock down to nearest MHz */
    115       1.1  nisimura 	clk = (clk / 1000) * 1000;
    116       1.1  nisimura 
    117       1.1  nisimura 	control = SDI_REG(SDI_CON);
    118       1.1  nisimura 	SDI_REG(SDI_CON) = control & ~SDICON_ENCLK;
    119       1.1  nisimura 
    120       1.1  nisimura 
    121       1.1  nisimura 	/* If the frequency is zero just keep the clock disabled */
    122       1.1  nisimura 	if (freq == 0)
    123       1.1  nisimura 		return 0;
    124       1.1  nisimura 
    125       1.1  nisimura 	for (div = 1; div <= 256; div++) {
    126       1.1  nisimura 		if ( clk / div <= freq) {
    127       1.1  nisimura 			DPRINTF(("Using divisor %d: %d/%d = %d\n", div, clk,
    128       1.1  nisimura 				 div, clk/div));
    129       1.1  nisimura 			clock_set = 1;
    130       1.1  nisimura 			SDI_REG(SDI_PRE) = div-1;
    131       1.1  nisimura 			break;
    132       1.1  nisimura 		}
    133       1.1  nisimura 	}
    134       1.1  nisimura 
    135       1.1  nisimura 	if (clock_set) {
    136       1.1  nisimura 		SDI_REG(SDI_CON) = control | SDICON_ENCLK;
    137       1.1  nisimura 		if (div-1 != SDI_REG(SDI_PRE)) {
    138       1.1  nisimura 			return 1;
    139       1.1  nisimura 		}
    140       1.1  nisimura 
    141       1.1  nisimura 		sdmmc_delay(74000/freq);
    142       1.1  nisimura 		/* Wait for 74 SDCLK */
    143       1.1  nisimura 		/* 1/freq is the length of a clock cycle,
    144       1.1  nisimura 		   so we have to wait 1/freq * 74 .
    145       1.1  nisimura 		   74000 / freq should express the delay in us.
    146       1.1  nisimura 		 */
    147       1.1  nisimura 		return 0;
    148       1.1  nisimura 	} else {
    149       1.1  nisimura 		return 1;
    150       1.1  nisimura 	}
    151       1.1  nisimura }
    152       1.1  nisimura 
    153       1.1  nisimura #define SSSDI_TRANSFER_NONE  0
    154       1.1  nisimura #define SSSDI_TRANSFER_READ  1
    155       1.1  nisimura #define SSSDI_TRANSFER_WRITE 2
    156       1.1  nisimura 
    157       1.1  nisimura void
    158       1.1  nisimura s3csd_exec_cmd(void *priv, struct sdmmc_command *cmd)
    159       1.1  nisimura {
    160       1.1  nisimura 	uint32_t cmd_control;
    161       1.1  nisimura 	int status = 0;
    162       1.1  nisimura 	uint32_t data_status;
    163       1.1  nisimura 	int transfer = SSSDI_TRANSFER_NONE;
    164       1.1  nisimura 
    165       1.1  nisimura 	DPRINTF(("s3csd_exec_cmd\n"));
    166       1.1  nisimura 
    167       1.1  nisimura 	SDI_REG(SDI_DAT_FSTA) = 0xFFFFFFFF;
    168       1.1  nisimura 	SDI_REG(SDI_DAT_STA) = 0xFFFFFFFF;
    169       1.1  nisimura 	SDI_REG(SDI_CMD_STA) = 0xFFFFFFFF;
    170       1.1  nisimura 
    171       1.1  nisimura 	SDI_REG(SDI_CMD_ARG) = cmd->c_arg;
    172       1.1  nisimura 
    173       1.1  nisimura 	cmd_control = (cmd->c_opcode & SDICMDCON_CMD_MASK) |
    174       1.1  nisimura 	  SDICMDCON_HOST_CMD | SDICMDCON_CMST;
    175       1.1  nisimura 	if (cmd->c_flags & SCF_RSP_PRESENT)
    176       1.1  nisimura 		cmd_control |= SDICMDCON_WAIT_RSP;
    177       1.1  nisimura 	if (cmd->c_flags & SCF_RSP_136)
    178       1.1  nisimura 		cmd_control |= SDICMDCON_LONG_RSP;
    179       1.1  nisimura 
    180       1.1  nisimura 	if (cmd->c_datalen > 0 && cmd->c_data != NULL) {
    181       1.1  nisimura 		/* TODO: Ensure that the above condition matches the semantics
    182       1.1  nisimura 		         of SDICMDCON_WITH_DATA*/
    183       1.1  nisimura 		DPRINTF(("DATA, datalen: %d, blk_size: %d, offset: %d\n", cmd->c_datalen,
    184       1.1  nisimura 			 cmd->c_blklen, cmd->c_arg));
    185       1.1  nisimura 		cmd_control |= SDICMDCON_WITH_DATA;
    186       1.1  nisimura 	}
    187       1.1  nisimura 
    188       1.1  nisimura 	if (cmd->c_opcode == MMC_STOP_TRANSMISSION) {
    189       1.1  nisimura 		cmd_control |= SDICMDCON_ABORT_CMD;
    190       1.1  nisimura 	}
    191       1.1  nisimura 
    192       1.1  nisimura 	SDI_REG(SDI_DTIMER) = 0x007FFFFF;
    193       1.1  nisimura 	SDI_REG(SDI_BSIZE) = cmd->c_blklen;
    194       1.1  nisimura 
    195       1.1  nisimura 	if ( (cmd->c_flags & SCF_CMD_READ) &&
    196       1.1  nisimura 	     (cmd_control & SDICMDCON_WITH_DATA)) {
    197       1.1  nisimura 		uint32_t data_control;
    198       1.1  nisimura 		DPRINTF(("Reading %d bytes\n", cmd->c_datalen));
    199       1.1  nisimura 		transfer = SSSDI_TRANSFER_READ;
    200       1.1  nisimura 
    201       1.1  nisimura 		data_control = SDIDATCON_DATMODE_RECEIVE | SDIDATCON_RACMD |
    202       1.1  nisimura 		  SDIDATCON_DTST | SDIDATCON_BLKMODE |
    203       1.1  nisimura 		  ((cmd->c_datalen / cmd->c_blklen) & SDIDATCON_BLKNUM_MASK) |
    204       1.1  nisimura 		  SDIDATCON_DATA_WORD;
    205       1.1  nisimura 
    206       1.1  nisimura 
    207       1.1  nisimura 		if (s3csdi_softc.width == 4) {
    208       1.1  nisimura 			data_control |= SDIDATCON_WIDEBUS;
    209       1.1  nisimura 		}
    210       1.1  nisimura 
    211       1.1  nisimura 		SDI_REG(SDI_DAT_CON) = data_control;
    212       1.1  nisimura 	} else if (cmd_control & SDICMDCON_WITH_DATA) {
    213       1.1  nisimura 		/* Write data */
    214       1.1  nisimura 
    215       1.1  nisimura 		uint32_t data_control;
    216       1.1  nisimura 		DPRINTF(("Writing %d bytes\n", cmd->c_datalen));
    217       1.1  nisimura 		DPRINTF(("Requesting %d blocks\n",
    218       1.1  nisimura 			 cmd->c_datalen / cmd->c_blklen));
    219       1.1  nisimura 		transfer = SSSDI_TRANSFER_WRITE;
    220       1.1  nisimura 		data_control = SDIDATCON_DATMODE_TRANSMIT | SDIDATCON_BLKMODE |
    221       1.1  nisimura 		  SDIDATCON_TARSP | SDIDATCON_DTST |
    222       1.1  nisimura 		  ((cmd->c_datalen / cmd->c_blklen) & SDIDATCON_BLKNUM_MASK) |
    223       1.1  nisimura 		  SDIDATCON_DATA_WORD;
    224       1.1  nisimura 
    225       1.1  nisimura /*		if (sc->width == 4) {
    226       1.1  nisimura 			data_control |= SDIDATCON_WIDEBUS;
    227       1.1  nisimura 			}*/
    228       1.1  nisimura 
    229       1.1  nisimura 		SDI_REG(SDI_DAT_CON) = data_control;
    230       1.1  nisimura 	}
    231       1.1  nisimura 
    232       1.1  nisimura 	DPRINTF(("SID_CMD_CON: 0x%X\n", cmd_control));
    233       1.1  nisimura 	/* Send command to SDI */
    234       1.1  nisimura 	SDI_REG(SDI_CMD_CON) = cmd_control;
    235       1.1  nisimura 	DPRINTF(("Status before cmd sent: 0x%X\n", SDI_REG(SDI_CMD_STA)));
    236       1.1  nisimura 	DPRINTF(("Waiting for command being sent\n"));
    237       1.1  nisimura 	while( !(SDI_REG(SDI_CMD_STA) & SDICMDSTA_CMD_SENT));
    238       1.1  nisimura 	DPRINTF(("Command has been sent\n"));
    239       1.1  nisimura 
    240       1.1  nisimura 	//SDI_REG(SDI_CMD_STA) |= SDICMDSTA_CMD_SENT;
    241       1.1  nisimura 
    242       1.1  nisimura 	if (!(cmd_control & SDICMDCON_WAIT_RSP)) {
    243       1.1  nisimura 		SDI_REG(SDI_CMD_STA) |= SDICMDSTA_CMD_SENT;
    244       1.1  nisimura 		cmd->c_flags |= SCF_ITSDONE;
    245       1.1  nisimura 		goto out;
    246       1.1  nisimura 	}
    247       1.1  nisimura 
    248       1.1  nisimura 	DPRINTF(("waiting for response\n"));
    249       1.1  nisimura 	while(1) {
    250       1.1  nisimura 		status = SDI_REG(SDI_CMD_STA);
    251       1.1  nisimura 		if (status & SDICMDSTA_RSP_FIN) {
    252       1.1  nisimura 			break;
    253       1.1  nisimura 		}
    254       1.1  nisimura 		if (status & SDICMDSTA_CMD_TIMEOUT) {
    255       1.1  nisimura 			break;
    256       1.1  nisimura 		}
    257       1.1  nisimura 	}
    258       1.1  nisimura 
    259       1.1  nisimura 	DPRINTF(("Status: 0x%X\n", status));
    260       1.1  nisimura 	if (status & SDICMDSTA_CMD_TIMEOUT) {
    261       1.1  nisimura 		cmd->c_error = ETIMEDOUT;
    262       1.1  nisimura 		DPRINTF(("Timeout waiting for response\n"));
    263       1.1  nisimura 		goto out;
    264       1.1  nisimura 	}
    265       1.1  nisimura 	DPRINTF(("Got Response\n"));
    266       1.1  nisimura 
    267       1.1  nisimura 	if (cmd->c_flags & SCF_RSP_136 ) {
    268       1.1  nisimura 		uint32_t w[4];
    269       1.1  nisimura 
    270       1.1  nisimura 		/* We store the response least significant word first */
    271       1.1  nisimura 		w[0] = SDI_REG(SDI_RSP3);
    272       1.1  nisimura 		w[1] = SDI_REG(SDI_RSP2);
    273       1.1  nisimura 		w[2] = SDI_REG(SDI_RSP1);
    274       1.1  nisimura 		w[3] = SDI_REG(SDI_RSP0);
    275       1.1  nisimura 
    276       1.1  nisimura 		/* The sdmmc subsystem expects that the response is delivered
    277       1.1  nisimura 		   without the lower 8 bits (CRC + '1' bit) */
    278       1.1  nisimura 		cmd->c_resp[0] = (w[0] >> 8) | ((w[1] & 0xFF) << 24);
    279       1.1  nisimura 		cmd->c_resp[1] = (w[1] >> 8) | ((w[2] & 0XFF) << 24);
    280       1.1  nisimura 		cmd->c_resp[2] = (w[2] >> 8) | ((w[3] & 0XFF) << 24);
    281       1.1  nisimura 		cmd->c_resp[3] = (w[3] >> 8);
    282       1.1  nisimura 
    283       1.1  nisimura 	} else {
    284       1.1  nisimura 		cmd->c_resp[0] = SDI_REG(SDI_RSP0);
    285       1.1  nisimura 		cmd->c_resp[1] = SDI_REG(SDI_RSP1);
    286       1.1  nisimura 	}
    287       1.1  nisimura 
    288       1.1  nisimura 	DPRINTF(("Response: %X %X %X %X\n",
    289       1.1  nisimura 		 cmd->c_resp[0],
    290       1.1  nisimura 		 cmd->c_resp[1],
    291       1.1  nisimura 		 cmd->c_resp[2],
    292       1.1  nisimura 		 cmd->c_resp[3]));
    293       1.1  nisimura 
    294       1.1  nisimura 	status = SDI_REG(SDI_DAT_CNT);
    295       1.1  nisimura 
    296       1.1  nisimura 	DPRINTF(("Remaining bytes of current block: %d\n",
    297       1.1  nisimura 		 SDIDATCNT_BLK_CNT(status)));
    298       1.1  nisimura 	DPRINTF(("Remaining Block Number          : %d\n",
    299       1.1  nisimura 		 SDIDATCNT_BLK_NUM_CNT(status)));
    300       1.1  nisimura 
    301       1.1  nisimura 	data_status = SDI_REG(SDI_DAT_STA);
    302       1.1  nisimura 
    303       1.1  nisimura 	DPRINTF(("SDI Data Status Register Before xfer: 0x%X\n", data_status));
    304       1.1  nisimura 
    305       1.1  nisimura 	if (data_status & SDIDATSTA_DATA_TIMEOUT) {
    306       1.1  nisimura 		cmd->c_error = ETIMEDOUT;
    307       1.1  nisimura 		DPRINTF(("Timeout waiting for data\n"));
    308       1.1  nisimura 		goto out;
    309       1.1  nisimura 	}
    310       1.1  nisimura 
    311       1.1  nisimura 
    312       1.1  nisimura 	if (transfer == SSSDI_TRANSFER_READ) {
    313       1.1  nisimura 		DPRINTF(("Waiting for transfer to complete\n"));
    314       1.1  nisimura 
    315       1.1  nisimura 		sssdi_perform_pio_read(cmd);
    316       1.1  nisimura 	} else if (transfer == SSSDI_TRANSFER_WRITE) {
    317       1.1  nisimura 
    318       1.1  nisimura /*		DPRINTF(("PIO WRITE\n"));
    319       1.1  nisimura 		sssdi_perform_pio_write(sc, cmd);
    320       1.1  nisimura 
    321       1.1  nisimura 		if (cmd->c_error == ETIMEDOUT)
    322       1.1  nisimura 		goto out;*/
    323       1.1  nisimura 	}
    324       1.1  nisimura 
    325       1.1  nisimura 
    326       1.1  nisimura 	/* Response has been received, and any data transfer needed has been
    327       1.1  nisimura 	   performed */
    328       1.1  nisimura 	cmd->c_flags |= SCF_ITSDONE;
    329       1.1  nisimura 
    330       1.1  nisimura  out:
    331       1.1  nisimura 
    332       1.1  nisimura 	data_status = SDI_REG(SDI_DAT_STA);
    333       1.1  nisimura 	DPRINTF(("SDI Data Status Register after execute: 0x%X\n", data_status));
    334       1.1  nisimura 
    335       1.1  nisimura 	/* Clear status register. Their are cleared on the
    336       1.1  nisimura 	   next sssdi_exec_command  */
    337       1.1  nisimura 	SDI_REG(SDI_CMD_STA) =  0xFFFFFFFF;
    338       1.1  nisimura 	SDI_REG(SDI_DAT_CON) =  0x0;
    339       1.1  nisimura }
    340       1.1  nisimura 
    341       1.1  nisimura void
    342       1.1  nisimura sssdi_perform_pio_read(struct sdmmc_command *cmd)
    343       1.1  nisimura {
    344       1.1  nisimura 	uint32_t status;
    345       1.1  nisimura 	uint32_t fifo_status;
    346       1.1  nisimura 	int count;
    347       1.1  nisimura 	uint32_t written;
    348       1.1  nisimura 	uint8_t *dest = (uint8_t*)cmd->c_data;
    349       1.1  nisimura 	int i;
    350       1.1  nisimura 
    351       1.1  nisimura 	written = 0;
    352       1.1  nisimura 
    353       1.1  nisimura 	while (written < cmd->c_datalen ) {
    354       1.1  nisimura 		/* Wait until the FIFO is full or has the final data.
    355       1.1  nisimura 		   In the latter case it might not get filled. */
    356       1.1  nisimura 		//status = sssdi_wait_intr(sc, SDI_FIFO_RX_FULL | SDI_FIFO_RX_LAST, 1000);
    357       1.1  nisimura 		//printf("Waiting for FIFO (got %d / %d)\n", written, cmd->c_datalen);
    358       1.1  nisimura 		do {
    359       1.1  nisimura 			status = SDI_REG(SDI_DAT_FSTA);
    360       1.1  nisimura 		} while( !(status & SDIDATFSTA_RF_FULL) && !(status & SDIDATFSTA_RF_LAST));
    361       1.1  nisimura 		//printf("Done\n");
    362       1.1  nisimura 
    363       1.1  nisimura 		fifo_status = SDI_REG(SDI_DAT_FSTA);
    364       1.1  nisimura 		count = SDIDATFSTA_FFCNT(fifo_status);
    365       1.1  nisimura 
    366       1.1  nisimura 		//printf("Writing %d bytes to %p\n", count, dest);
    367       1.1  nisimura 		for(i=0; i<count; i+=4) {
    368       1.1  nisimura 			uint32_t buf;
    369       1.1  nisimura 
    370       1.1  nisimura 			buf = SDI_REG(SDI_DAT_LI_W);
    371       1.1  nisimura 			*dest = (buf & 0xFF); dest++;
    372       1.1  nisimura 			*dest = (buf >> 8) & 0xFF; dest++;
    373       1.1  nisimura 			*dest = (buf >> 16) & 0xFF; dest++;
    374       1.1  nisimura 			*dest = (buf >> 24) & 0xFF; dest++;
    375       1.1  nisimura 			written += 4;
    376       1.1  nisimura 		}
    377       1.1  nisimura 	}
    378       1.1  nisimura }
    379       1.1  nisimura 
    380       1.1  nisimura #if 0
    381       1.1  nisimura void
    382       1.1  nisimura sssdi_perform_pio_write(struct sdmmc_command *cmd)
    383       1.1  nisimura {
    384       1.1  nisimura 	uint32_t status;
    385       1.1  nisimura 	uint32_t fifo_status;
    386       1.1  nisimura 	int count;
    387       1.1  nisimura 	uint32_t written;
    388       1.1  nisimura 	uint32_t *dest = (uint32_t*)cmd->c_data;
    389       1.1  nisimura 
    390       1.1  nisimura 	written = 0;
    391       1.1  nisimura 
    392       1.1  nisimura 	while (written < cmd->c_datalen ) {
    393       1.1  nisimura 		/* Wait until the FIFO is full or has the final data.
    394       1.1  nisimura 		   In the latter case it might not get filled. */
    395       1.1  nisimura 		DPRINTF(("Waiting for FIFO to become empty\n"));
    396       1.1  nisimura 		status = sssdi_wait_intr(sc, SDI_FIFO_TX_EMPTY, 1000);
    397       1.1  nisimura 
    398       1.1  nisimura 		fifo_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_FSTA);
    399       1.1  nisimura 		DPRINTF(("PIO Write FIFO Status: 0x%X\n", fifo_status));
    400       1.1  nisimura 		count = 64-SDIDATFSTA_FFCNT(fifo_status);
    401       1.1  nisimura 
    402       1.1  nisimura 		status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_CNT);
    403       1.1  nisimura 		DPRINTF(("Remaining bytes of current block: %d\n",
    404       1.1  nisimura 			 SDIDATCNT_BLK_CNT(status)));
    405       1.1  nisimura 		DPRINTF(("Remaining Block Number          : %d\n",
    406       1.1  nisimura 			 SDIDATCNT_BLK_NUM_CNT(status)));
    407       1.1  nisimura 
    408       1.1  nisimura 
    409       1.1  nisimura 		status = bus_space_read_4(sc->iot,sc->ioh, SDI_DAT_STA);
    410       1.1  nisimura 		DPRINTF(("PIO Write Data Status: 0x%X\n", status));
    411       1.1  nisimura 
    412       1.1  nisimura 		if (status & SDIDATSTA_DATA_TIMEOUT) {
    413       1.1  nisimura 			cmd->c_error = ETIMEDOUT;
    414       1.1  nisimura 			/* Acknowledge the timeout*/
    415       1.1  nisimura 			bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_STA,
    416       1.1  nisimura 					  SDIDATSTA_DATA_TIMEOUT);
    417       1.3       chs 			printf("%s: Data timeout\n", device_xname(sc->dev));
    418       1.1  nisimura 			break;
    419       1.1  nisimura 		}
    420       1.1  nisimura 
    421       1.1  nisimura 		DPRINTF(("Filling FIFO with %d bytes\n", count));
    422       1.1  nisimura 		for(int i=0; i<count; i+=4) {
    423       1.1  nisimura 			bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_LI_W, *dest);
    424       1.1  nisimura 			written += 4;
    425       1.1  nisimura 			dest++;
    426       1.1  nisimura 		}
    427       1.1  nisimura 	}
    428       1.1  nisimura }
    429       1.1  nisimura #endif
    430       1.1  nisimura 
    431       1.1  nisimura int
    432       1.1  nisimura s3csd_host_ocr(void *priv)
    433       1.1  nisimura {
    434       1.1  nisimura 	return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V;
    435       1.1  nisimura }
    436       1.1  nisimura 
    437       1.1  nisimura int
    438       1.1  nisimura s3csd_bus_power(void *priv, int ocr)
    439       1.1  nisimura {
    440       1.1  nisimura 	return 0;
    441       1.1  nisimura }
    442       1.1  nisimura 
    443       1.1  nisimura int
    444       1.1  nisimura s3csd_bus_width(void *priv, int width)
    445       1.1  nisimura {
    446       1.1  nisimura 	s3csdi_softc.width = width;
    447       1.1  nisimura 	return 0;
    448       1.1  nisimura }
    449       1.1  nisimura 
    450       1.1  nisimura int
    451       1.1  nisimura s3csd_get_max_bus_clock(void *priv)
    452       1.1  nisimura {
    453       1.1  nisimura 	return pclk / 1;
    454       1.1  nisimura }
    455