Home | History | Annotate | Line # | Download | only in t_sh7706lan
ssumci.c revision 1.2.16.1
      1 /*	$NetBSD: ssumci.c,v 1.2.16.1 2014/01/12 12:38:37 bouyer Exp $	*/
      2 
      3 /*-
      4  * Copyright (C) 2010 NONAKA Kimihiro <nonaka (at) netbsd.org>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 /*
     29  * driver to access MMC/SD card
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: ssumci.c,v 1.2.16.1 2014/01/12 12:38:37 bouyer Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/device.h>
     37 #include <sys/systm.h>
     38 #include <sys/malloc.h>
     39 #include <sys/kernel.h>
     40 #include <sys/proc.h>
     41 #include <sys/bus.h>
     42 #include <sys/intr.h>
     43 
     44 #include <sh3/devreg.h>
     45 #include <sh3/pfcreg.h>
     46 #include <sh3/scireg.h>
     47 
     48 #include <dev/sdmmc/sdmmcvar.h>
     49 #include <dev/sdmmc/sdmmcchip.h>
     50 
     51 #include <machine/autoconf.h>
     52 
     53 #include <evbsh3/t_sh7706lan/t_sh7706lanvar.h>
     54 
     55 #ifdef SSUMCI_DEBUG
     56 int ssumci_debug = 1;
     57 #define DPRINTF(n,s)	do { if ((n) <= ssumci_debug) printf s; } while (0)
     58 #else
     59 #define DPRINTF(n,s)	do {} while (0)
     60 #endif
     61 
     62 static int	ssumci_host_reset(sdmmc_chipset_handle_t);
     63 static uint32_t	ssumci_host_ocr(sdmmc_chipset_handle_t);
     64 static int	ssumci_host_maxblklen(sdmmc_chipset_handle_t);
     65 static int	ssumci_card_detect(sdmmc_chipset_handle_t);
     66 static int	ssumci_write_protect(sdmmc_chipset_handle_t);
     67 static int	ssumci_bus_power(sdmmc_chipset_handle_t, uint32_t);
     68 static int	ssumci_bus_clock(sdmmc_chipset_handle_t, int);
     69 static int	ssumci_bus_width(sdmmc_chipset_handle_t, int);
     70 static void	ssumci_exec_command(sdmmc_chipset_handle_t,
     71 		    struct sdmmc_command *);
     72 
     73 static struct sdmmc_chip_functions ssumci_chip_functions = {
     74 	/* host controller reset */
     75 	.host_reset		= ssumci_host_reset,
     76 
     77 	/* host controller capabilities */
     78 	.host_ocr		= ssumci_host_ocr,
     79 	.host_maxblklen		= ssumci_host_maxblklen,
     80 
     81 	/* card detection */
     82 	.card_detect		= ssumci_card_detect,
     83 
     84 	/* write protect */
     85 	.write_protect		= ssumci_write_protect,
     86 
     87 	/* bus power, clock frequency, width */
     88 	.bus_power		= ssumci_bus_power,
     89 	.bus_clock		= ssumci_bus_clock,
     90 	.bus_width		= ssumci_bus_width,
     91 
     92 	/* command execution */
     93 	.exec_command		= ssumci_exec_command,
     94 
     95 	/* card interrupt */
     96 	.card_enable_intr	= NULL,
     97 	.card_intr_ack		= NULL,
     98 };
     99 
    100 static void	ssumci_spi_initialize(sdmmc_chipset_handle_t);
    101 
    102 static struct sdmmc_spi_chip_functions ssumci_spi_chip_functions = {
    103 	.initialize		= ssumci_spi_initialize,
    104 };
    105 
    106 #define	CSR_SET_1(reg,set,mask) 					\
    107 do {									\
    108 	uint8_t _r;							\
    109 	_r = _reg_read_1((reg));					\
    110 	_r &= ~(mask);							\
    111 	_r |= (set);							\
    112 	_reg_write_1((reg), _r);					\
    113 } while (/*CONSTCOND*/0)
    114 
    115 #define	CSR_SET_2(reg,set,mask) 					\
    116 do {									\
    117 	uint16_t _r;							\
    118 	_r = _reg_read_2((reg));					\
    119 	_r &= ~(mask);							\
    120 	_r |= (set);							\
    121 	_reg_write_2((reg), _r);					\
    122 } while (/*CONSTCOND*/0)
    123 
    124 #define	CSR_CLR_1(reg,clr)	 					\
    125 do {									\
    126 	uint8_t _r;							\
    127 	_r = _reg_read_1((reg));					\
    128 	_r &= ~(clr);							\
    129 	_reg_write_1((reg), _r);					\
    130 } while (/*CONSTCOND*/0)
    131 
    132 #define	CSR_CLR_2(reg,clr)	 					\
    133 do {									\
    134 	uint16_t _r;							\
    135 	_r = _reg_read_2((reg));					\
    136 	_r &= ~(clr);							\
    137 	_reg_write_2((reg), _r);					\
    138 } while (/*CONSTCOND*/0)
    139 
    140 #define SCPCR_CLK_MASK	0x000C
    141 #define SCPCR_CLK_IN	0x000C
    142 #define SCPCR_CLK_OUT	0x0004
    143 #define SCPDR_CLK	0x02
    144 #define SCPCR_DAT_MASK	0x0003
    145 #define SCPCR_DAT_IN	0x0003
    146 #define SCPCR_DAT_OUT	0x0001
    147 #define SCPDR_DAT	0x01
    148 #define SCPCR_CMD_MASK	0x0030
    149 #define SCPCR_CMD_IN	0x0030
    150 #define SCPCR_CMD_OUT	0x0010
    151 #define SCPDR_CMD	0x04
    152 #define	SCPCR_CS_MASK	0x000C
    153 #define	SCPCR_CS_OUT	0x0004
    154 #define	SCPDR_CS	0x02
    155 #define	SCPCR_EJECT	0x00C0
    156 #define	SCPDR_EJECT	0x08
    157 
    158 #define MMC_TIME_OVER	20000
    159 
    160 struct ssumci_softc {
    161 	device_t sc_dev;
    162 	device_t sc_sdmmc;
    163 };
    164 
    165 static int ssumci_match(device_t, cfdata_t, void *);
    166 static void ssumci_attach(device_t, device_t, void *);
    167 
    168 CFATTACH_DECL_NEW(ssumci, sizeof(struct ssumci_softc),
    169     ssumci_match, ssumci_attach, NULL, NULL);
    170 
    171 static void ssumci_cmd_cfgread(struct ssumci_softc *, struct sdmmc_command *);
    172 static void ssumci_cmd_read(struct ssumci_softc *, struct sdmmc_command *);
    173 static void ssumci_cmd_write(struct ssumci_softc *, struct sdmmc_command *);
    174 
    175 #define	SSUMCI_SPIDR	0xb0008000
    176 #define	SSUMCI_SPISR	0xb0008002
    177 #define	SSUMCI_SPIBR	0xb0008004
    178 
    179 static inline void
    180 ssumci_wait(void)
    181 {
    182 
    183 	while (_reg_read_1(SSUMCI_SPISR) == 0x00)
    184 		continue;
    185 }
    186 
    187 static inline uint8_t
    188 ssumci_getc(void)
    189 {
    190 
    191 	ssumci_wait();
    192 	return _reg_read_1(SSUMCI_SPIBR);
    193 }
    194 
    195 static inline void
    196 ssumci_putc(uint8_t v)
    197 {
    198 
    199 	_reg_write_1(SSUMCI_SPIDR, v);
    200 	ssumci_wait();
    201 }
    202 
    203 /*ARGSUSED*/
    204 static int
    205 ssumci_match(device_t parent, cfdata_t cf, void *aux)
    206 {
    207 	struct mainbus_attach_args *maa = (struct mainbus_attach_args *)aux;
    208 
    209 	if (strcmp(maa->ma_name, "ssumci") != 0)
    210 		return 0;
    211 	if (!IS_SH7706LSR)
    212 		return 0;
    213 	return 1;
    214 }
    215 
    216 /*ARGSUSED*/
    217 static void
    218 ssumci_attach(device_t parent, device_t self, void *aux)
    219 {
    220 	struct ssumci_softc *sc = device_private(self);
    221 	struct sdmmcbus_attach_args saa;
    222 
    223 	sc->sc_dev = self;
    224 
    225 	aprint_naive("\n");
    226 	aprint_normal(": SPI MMC controller\n");
    227 
    228 	/* setup */
    229 	CSR_SET_2(SH7709_SCPCR, SCPCR_CS_OUT, SCPCR_CS_MASK);
    230 
    231 	/*
    232 	 * Attach the generic SD/MMC bus driver.  (The bus driver must
    233 	 * not invoke any chipset functions before it is attached.)
    234 	 */
    235 	memset(&saa, 0, sizeof(saa));
    236 	saa.saa_busname = "sdmmc";
    237 	saa.saa_sct = &ssumci_chip_functions;
    238 	saa.saa_spi_sct = &ssumci_spi_chip_functions;
    239 	saa.saa_sch = sc;
    240 	saa.saa_clkmin = 400;
    241 	saa.saa_clkmax = 400;
    242 	saa.saa_caps = SMC_CAPS_SPI_MODE
    243 	               | SMC_CAPS_SINGLE_ONLY
    244 	               | SMC_CAPS_POLL_CARD_DET;
    245 
    246 	sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL);
    247 	if (sc->sc_sdmmc == NULL)
    248 		aprint_error_dev(sc->sc_dev, "couldn't attach bus\n");
    249 }
    250 
    251 /*
    252  * Reset the host controller.  Called during initialization, when
    253  * cards are removed, upon resume, and during error recovery.
    254  */
    255 /*ARGSUSED*/
    256 static int
    257 ssumci_host_reset(sdmmc_chipset_handle_t sch)
    258 {
    259 
    260 	return 0;
    261 }
    262 
    263 /*ARGSUSED*/
    264 static uint32_t
    265 ssumci_host_ocr(sdmmc_chipset_handle_t sch)
    266 {
    267 
    268 	return MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V;
    269 }
    270 
    271 /*ARGSUSED*/
    272 static int
    273 ssumci_host_maxblklen(sdmmc_chipset_handle_t sch)
    274 {
    275 
    276 	return 512;
    277 }
    278 
    279 /*ARGSUSED*/
    280 static int
    281 ssumci_card_detect(sdmmc_chipset_handle_t sch)
    282 {
    283 	uint8_t reg;
    284 	int s;
    285 
    286 	s = splsdmmc();
    287 	CSR_SET_2(SH7709_SCPCR, SCPCR_EJECT, 0);
    288 	reg = _reg_read_1(SH7709_SCPDR);
    289 	splx(s);
    290 
    291 	return !(reg & SCPDR_EJECT);
    292 }
    293 
    294 /*ARGSUSED*/
    295 static int
    296 ssumci_write_protect(sdmmc_chipset_handle_t sch)
    297 {
    298 
    299 	return 0;	/* non-protect */
    300 }
    301 
    302 /*
    303  * Set or change SD bus voltage and enable or disable SD bus power.
    304  * Return zero on success.
    305  */
    306 /*ARGSUSED*/
    307 static int
    308 ssumci_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
    309 {
    310 
    311 	if ((ocr & (MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V)) == 0)
    312 		return 1;
    313 
    314 	/*XXX???*/
    315 	return 0;
    316 }
    317 
    318 /*
    319  * Set or change MMCLK frequency or disable the MMC clock.
    320  * Return zero on success.
    321  */
    322 /*ARGSUSED*/
    323 static int
    324 ssumci_bus_clock(sdmmc_chipset_handle_t sch, int freq)
    325 {
    326 
    327 	return 0;
    328 }
    329 
    330 /*ARGSUSED*/
    331 static int
    332 ssumci_bus_width(sdmmc_chipset_handle_t sch, int width)
    333 {
    334 
    335 	if (width != 1)
    336 		return 1;
    337 	return 0;
    338 }
    339 
    340 /*ARGSUSED*/
    341 static void
    342 ssumci_spi_initialize(sdmmc_chipset_handle_t sch)
    343 {
    344 	int i, s;
    345 
    346 	s = splsdmmc();
    347 	CSR_SET_1(SH7709_SCPDR, SCPDR_CS, 0);
    348 	for (i = 0; i < 10; i++) {
    349 		ssumci_putc(0xff);
    350 	}
    351 	CSR_CLR_1(SH7709_SCPDR, SCPDR_CS);
    352 	splx(s);
    353 }
    354 
    355 static void
    356 ssumci_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
    357 {
    358 	struct ssumci_softc *sc = (struct ssumci_softc *)sch;
    359 	uint16_t resp;
    360 	int timo;
    361 	int s;
    362 
    363 	DPRINTF(1,("%s: start cmd %d arg=%#x data=%p dlen=%d flags=%#x\n",
    364 	    device_xname(sc->sc_dev), cmd->c_opcode, cmd->c_arg, cmd->c_data,
    365 	    cmd->c_datalen, cmd->c_flags));
    366 
    367 	s = splsdmmc();
    368 
    369 	ssumci_putc(0xff);
    370 	ssumci_putc(0x40 | (cmd->c_opcode & 0x3f));
    371 	ssumci_putc((cmd->c_arg >> 24) & 0xff);
    372 	ssumci_putc((cmd->c_arg >> 16) & 0xff);
    373 	ssumci_putc((cmd->c_arg >> 8) & 0xff);
    374 	ssumci_putc((cmd->c_arg >> 0) & 0xff);
    375 	ssumci_putc((cmd->c_opcode == MMC_GO_IDLE_STATE) ? 0x95 :
    376 	    (cmd->c_opcode == SD_SEND_IF_COND) ? 0x87 : 0); /* CRC */
    377 
    378 	for (timo = MMC_TIME_OVER; timo > 0; timo--) {
    379 		resp = ssumci_getc();
    380 		if (!(resp & 0x80) && timo <= (MMC_TIME_OVER - 2))
    381 			break;
    382 	}
    383 	if (timo == 0) {
    384 		DPRINTF(1,(sc->sc_dev, "response timeout\n"));
    385 		cmd->c_error = ETIMEDOUT;
    386 		goto out;
    387 	}
    388 
    389 	if (ISSET(cmd->c_flags, SCF_RSP_SPI_S2)) {
    390 		resp |= (uint16_t) ssumci_getc() << 8;
    391 	} else if (ISSET(cmd->c_flags, SCF_RSP_SPI_B4)) {
    392 		cmd->c_resp[1] =  (uint32_t) ssumci_getc() << 24;
    393 		cmd->c_resp[1] |= (uint32_t) ssumci_getc() << 16;
    394 		cmd->c_resp[1] |= (uint32_t) ssumci_getc() << 8;
    395 		cmd->c_resp[1] |= (uint32_t) ssumci_getc();
    396 		DPRINTF(1, ("R3 resp: %#x\n", cmd->c_resp[1]));
    397 	}
    398 	cmd->c_resp[0] = resp;
    399 	if (resp != 0 && resp != R1_SPI_IDLE) {
    400 		DPRINTF(1,("response error: %#x\n", resp));
    401 		cmd->c_error = EIO;
    402 		goto out;
    403 	}
    404 	DPRINTF(1, ("R1 resp: %#x\n", resp));
    405 
    406 	if (cmd->c_datalen > 0) {
    407 		if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
    408 			/* XXX: swap in this place? */
    409 			if (cmd->c_opcode == MMC_SEND_CID ||
    410 			    cmd->c_opcode == MMC_SEND_CSD) {
    411 				sdmmc_response res;
    412 				uint32_t *p = cmd->c_data;
    413 
    414 				ssumci_cmd_cfgread(sc, cmd);
    415 				res[0] = be32toh(p[3]);
    416 				res[1] = be32toh(p[2]);
    417 				res[2] = be32toh(p[1]);
    418 				res[3] = be32toh(p[0]);
    419 				memcpy(p, &res, sizeof(res));
    420 			} else {
    421 				ssumci_cmd_read(sc, cmd);
    422 			}
    423 		} else {
    424 			ssumci_cmd_write(sc, cmd);
    425 		}
    426 	} else {
    427 		ssumci_wait();
    428 	}
    429 
    430 out:
    431 	SET(cmd->c_flags, SCF_ITSDONE);
    432 	splx(s);
    433 
    434 	DPRINTF(1,("%s: cmd %d done (flags=%#x error=%d)\n",
    435 	  device_xname(sc->sc_dev), cmd->c_opcode, cmd->c_flags, cmd->c_error));
    436 }
    437 
    438 static void
    439 ssumci_cmd_cfgread(struct ssumci_softc *sc, struct sdmmc_command *cmd)
    440 {
    441 	u_char *data = cmd->c_data;
    442 	int timo;
    443 	int c;
    444 	int i;
    445 
    446 	/* wait data token */
    447 	for (timo = MMC_TIME_OVER; timo > 0; timo--) {
    448 		c = ssumci_getc();
    449 		if (c != 0xff)
    450 			break;
    451 	}
    452 	if (timo == 0) {
    453 		aprint_error_dev(sc->sc_dev, "cfg read timeout\n");
    454 		cmd->c_error = ETIMEDOUT;
    455 		return;
    456 	}
    457 	if (c != 0xfe) {
    458 		aprint_error_dev(sc->sc_dev, "cfg read error (data=%#x)\n", c);
    459 		cmd->c_error = EIO;
    460 		return;
    461 	}
    462 
    463 	/* data read */
    464 	data[0] = '\0'; /* XXXFIXME!!! */
    465 	for (i = 1 /* XXXFIXME!!!*/ ; i < cmd->c_datalen; i++) {
    466 		data[i] = ssumci_getc();
    467 	}
    468 
    469 	(void) ssumci_getc();
    470 	(void) ssumci_getc();
    471 	ssumci_wait();
    472 
    473 #ifdef SSUMCI_DEBUG
    474 	sdmmc_dump_data(NULL, cmd->c_data, cmd->c_datalen);
    475 #endif
    476 }
    477 
    478 static void
    479 ssumci_cmd_read(struct ssumci_softc *sc, struct sdmmc_command *cmd)
    480 {
    481 	u_char *data = cmd->c_data;
    482 	int timo;
    483 	int c;
    484 	int i;
    485 
    486 	/* wait data token */
    487 	for (timo = MMC_TIME_OVER; timo > 0; timo--) {
    488 		c = ssumci_getc();
    489 		if (c != 0xff)
    490 			break;
    491 	}
    492 	if (timo == 0) {
    493 		aprint_error_dev(sc->sc_dev, "read timeout\n");
    494 		cmd->c_error = ETIMEDOUT;
    495 		return;
    496 	}
    497 	if (c != 0xfe) {
    498 		aprint_error_dev(sc->sc_dev, "read error (data=%#x)\n", c);
    499 		cmd->c_error = EIO;
    500 		return;
    501 	}
    502 
    503 	/* data read */
    504 	for (i = 0; i < cmd->c_datalen; i++) {
    505 		data[i] = ssumci_getc();
    506 	}
    507 
    508 	/* ignore CRC */
    509 	(void) ssumci_getc();
    510 	(void) ssumci_getc();
    511 	ssumci_wait();
    512 
    513 #ifdef SSUMCI_DEBUG
    514 	sdmmc_dump_data(NULL, cmd->c_data, cmd->c_datalen);
    515 #endif
    516 }
    517 
    518 static void
    519 ssumci_cmd_write(struct ssumci_softc *sc, struct sdmmc_command *cmd)
    520 {
    521 	u_char *data = cmd->c_data;
    522 	int timo;
    523 	int c;
    524 	int i;
    525 
    526 	ssumci_wait();
    527 	ssumci_putc(0xfe);
    528 
    529 	/* data write */
    530 	for (i = 0; i < cmd->c_datalen; i++) {
    531 		ssumci_putc(data[i]);
    532 	}
    533 
    534 	/* dummy CRC */
    535 	ssumci_putc(0);
    536 	ssumci_putc(0);
    537 	ssumci_putc(0xff);
    538 	if ((_reg_read_1(SSUMCI_SPIDR) & 0x0f) != 5) {
    539 		aprint_error_dev(sc->sc_dev, "write error\n");
    540 		cmd->c_error = EIO;
    541 		return;
    542 	}
    543 
    544 	for (timo = 0x7fffffff; timo > 0; timo--) {
    545 		ssumci_putc(0xff);
    546 		c = _reg_read_1(SSUMCI_SPIDR);
    547 		if (c == 0xff)
    548 			break;
    549 	}
    550 	if (timo == 0) {
    551 		aprint_error_dev(sc->sc_dev, "write timeout\n");
    552 		cmd->c_error = ETIMEDOUT;
    553 	}
    554 }
    555