Home | History | Annotate | Line # | Download | only in imx
imx23_ssp.c revision 1.1
      1 /* $Id: imx23_ssp.c,v 1.1 2012/11/20 19:06:14 jkunz Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Petri Laakso.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/param.h>
     33 #include <sys/types.h>
     34 #include <sys/bus.h>
     35 #include <sys/cdefs.h>
     36 #include <sys/cpu.h>
     37 #include <sys/device.h>
     38 #include <sys/errno.h>
     39 #include <sys/systm.h>
     40 
     41 #include <arm/pic/picvar.h>
     42 
     43 #include <arm/imx/imx23_apbdma.h>
     44 #include <arm/imx/imx23_icollreg.h>
     45 #include <arm/imx/imx23_sspreg.h>
     46 #include <arm/imx/imx23var.h>
     47 
     48 #include <dev/sdmmc/sdmmcchip.h>
     49 #include <dev/sdmmc/sdmmcreg.h>
     50 #include <dev/sdmmc/sdmmcvar.h>
     51 
     52 /*
     53  * SD/MMC host controller driver for i.MX233.
     54  */
     55 
     56 struct issp_softc {
     57 	device_t sc_dev;
     58 	bus_space_tag_t sc_iot;
     59 	bus_space_handle_t sc_hdl;
     60 	device_t sc_sdmmc;
     61 	device_t dmac;
     62 };
     63 
     64 static int	issp_match(device_t, cfdata_t, void *);
     65 static void	issp_attach(device_t, device_t, void *);
     66 static int	issp_activate(device_t, enum devact);
     67 
     68 /* sdmmc chip function prototypes. */
     69 static int	issp_host_reset(sdmmc_chipset_handle_t);
     70 static uint32_t	issp_host_ocr(sdmmc_chipset_handle_t);
     71 static int	issp_host_maxblklen(sdmmc_chipset_handle_t);
     72 static int	issp_card_detect(sdmmc_chipset_handle_t);
     73 static int	issp_write_protect(sdmmc_chipset_handle_t);
     74 static int	issp_bus_power(sdmmc_chipset_handle_t, uint32_t);
     75 static int	issp_bus_clock(sdmmc_chipset_handle_t, int);
     76 static int	issp_bus_width(sdmmc_chipset_handle_t, int);
     77 static int	issp_bus_rod(sdmmc_chipset_handle_t, int);
     78 static void	issp_exec_command(sdmmc_chipset_handle_t,
     79 			struct sdmmc_command *);
     80 static void	issp_card_enable_intr(sdmmc_chipset_handle_t, int);
     81 static void	issp_card_intr_ack(sdmmc_chipset_handle_t);
     82 
     83 /* Used from the above callbacks. */
     84 static void	issp_reset(struct issp_softc *);
     85 static void	issp_init(struct issp_softc *);
     86 static uint32_t	issp_set_sck(struct issp_softc *, uint32_t target);
     87 
     88 #define SSP_SOFT_RST_LOOP 455	/* At least 1 us ... */
     89 
     90 CFATTACH_DECL3_NEW(ssp,
     91 	sizeof(struct issp_softc),
     92 	issp_match,
     93 	issp_attach,
     94 	NULL,
     95 	issp_activate,
     96 	NULL,
     97 	NULL,
     98 	0);
     99 
    100 static struct sdmmc_chip_functions issp_functions = {
    101 	.host_reset	= issp_host_reset,
    102 	.host_ocr	= issp_host_ocr,
    103 	.host_maxblklen	= issp_host_maxblklen,
    104 	.card_detect	= issp_card_detect,
    105 	.write_protect	= issp_write_protect,
    106 	.bus_power	= issp_bus_power,
    107 	.bus_clock	= issp_bus_clock,
    108 	.bus_width	= issp_bus_width,
    109 	.bus_rod	= issp_bus_rod,
    110 	.exec_command	= issp_exec_command,
    111 	.card_enable_intr = issp_card_enable_intr,
    112 	.card_intr_ack	= issp_card_intr_ack
    113 };
    114 
    115 #define SSP_READ(sc, reg)						\
    116 	bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
    117 #define SSP_WRITE(sc, reg, val)						\
    118 	bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
    119 
    120 #define SSP_CLK			96000000 /* CLK_SSP from PLL is 96 MHz */
    121 #define SSP_CLK_MIN		2	 /* 2 kHz */
    122 #define SSP_CLK_MAX		48000	 /* 48 MHz */
    123 /* SSP_CMD_TIMEOUT is calculated as (1.0/SSP_SCK)*(SSP_CMD_TIMEOUT*4096) */
    124 #define SSP_CMD_TIMEOUT		0xffff	/* 2.8 seconds. */
    125 #define SSP_STATUS_ERR (HW_SSP_STATUS_RESP_CRC_ERR |			\
    126 			HW_SSP_STATUS_RESP_ERR |			\
    127 			HW_SSP_STATUS_RESP_TIMEOUT |			\
    128 			HW_SSP_STATUS_DATA_CRC_ERR |			\
    129 			HW_SSP_STATUS_TIMEOUT)
    130 
    131 static int
    132 issp_match(device_t parent, cfdata_t match, void *aux)
    133 {
    134 	struct apb_attach_args *aa = aux;
    135 
    136 	if ((aa->aa_addr == HW_SSP1_BASE) && (aa->aa_size == HW_SSP1_SIZE))
    137 		return 1;
    138 
    139 	if ((aa->aa_addr == HW_SSP2_BASE) && (aa->aa_size == HW_SSP2_SIZE))
    140 		return 1;
    141 
    142 	return 0;
    143 }
    144 
    145 static void
    146 issp_attach(device_t parent, device_t self, void *aux)
    147 {
    148 	static int issp_attached = 0;
    149 	struct issp_softc *sc = device_private(self);
    150 	struct apb_softc *scp = device_private(parent);
    151 	struct apb_attach_args *aa = aux;
    152 	struct sdmmcbus_attach_args saa;
    153 
    154 
    155 	if (issp_attached)
    156 		return;
    157 
    158 //XXX:
    159 	if (scp == NULL)
    160 		printf("ISSP_ATTACH: scp == NULL\n");
    161 	if (scp->dmac == NULL)
    162 		printf("ISSP_ATTACH: scp->dmac == NULL\n");
    163 
    164 	sc->sc_dev = self;
    165 	sc->sc_iot = aa->aa_iot;
    166 	sc->dmac = scp->dmac;
    167 
    168 	if (bus_space_map(sc->sc_iot,
    169 	    aa->aa_addr, aa->aa_size, 0, &(sc->sc_hdl))) {
    170 		aprint_error_dev(sc->sc_dev, "unable to map bus space\n");
    171 		return;
    172 	}
    173 
    174 	issp_reset(sc);
    175 	issp_init(sc);
    176 
    177 	uint32_t issp_vers = SSP_READ(sc, HW_SSP_VERSION);
    178 	aprint_normal(": SSP Block v%" __PRIuBIT ".%" __PRIuBIT "\n",
    179 	    __SHIFTOUT(issp_vers, HW_SSP_VERSION_MAJOR),
    180 	    __SHIFTOUT(issp_vers, HW_SSP_VERSION_MINOR));
    181 
    182 	saa.saa_busname = "sdmmc";
    183 	saa.saa_sct	= &issp_functions;
    184 	saa.saa_spi_sct	= NULL;
    185 	saa.saa_sch	= sc;
    186 	saa.saa_dmat	= aa->aa_dmat;
    187 	saa.saa_clkmin	= SSP_CLK_MIN;
    188 	saa.saa_clkmax	= SSP_CLK_MAX;
    189 	saa.saa_caps	= SMC_CAPS_4BIT_MODE | SMC_CAPS_DMA;
    190 
    191 	sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL);
    192 	if (sc->sc_sdmmc == NULL) {
    193 		aprint_error_dev(sc->sc_dev, "unable to attach sdmmc\n");
    194 		return;
    195 	}
    196 
    197 	issp_attached = 1;
    198 
    199 	return;
    200 }
    201 
    202 static int
    203 issp_activate(device_t self, enum devact act)
    204 {
    205 	return EOPNOTSUPP;
    206 }
    207 
    208 /*
    209  * sdmmc chip functions.
    210  */
    211 static int
    212 issp_host_reset(sdmmc_chipset_handle_t sch)
    213 {
    214 	struct issp_softc *sc = sch;
    215 
    216 	issp_reset(sc);
    217 
    218 	return 0;
    219 }
    220 
    221 static uint32_t
    222 issp_host_ocr(sdmmc_chipset_handle_t sch)
    223 {
    224 	/* SSP supports at least 3.2-3.3v */
    225 	return MMC_OCR_3_2V_3_3V;
    226 }
    227 
    228 static int
    229 issp_host_maxblklen(sdmmc_chipset_handle_t sch)
    230 {
    231 	/* XXX: This value was made up. */
    232 	return 512;
    233 }
    234 
    235 /*
    236  * Called at the beginning of sdmmc_task_thread to detect the presence
    237  * of the SD card.
    238  */
    239 static int
    240 issp_card_detect(sdmmc_chipset_handle_t sch)
    241 {
    242 	/* struct issp_softc *sc = sch;
    243 	 *
    244 	 * In the perfect world I'll just:
    245 	 * 	return SSP_READ(sc, HW_SSP_STATUS) & HW_SSP_STATUS_CARD_DETECT;
    246 	 * and call it a day.
    247 	 *
    248 	 * But on i.MX233 OLinuXino MAXI, SSP1_DETECT is not used for the SD
    249 	 * card detection but SSP1_DATA3 is, as Tsvetan put it:
    250 	 *
    251 	 * < Tsvetan> if you want to know if SD card is inserted watch
    252 	 * 		CD/DAT3/CS port
    253 	 * < Tsvetan> without card there is R20 weak pulldown
    254 	 * < Tsvetan> all cards have 40K pullup to this pin
    255 	 * < Tsvetan> so when card is inserted you will read it high
    256 	 *
    257 	 * Which means I should to do something like this:
    258 	 * 	#if BOARDTYPE == MAXI (Possibly MINI & MICRO)
    259 	 * 		return GPIO_READ(PIN_125) & PIN_125
    260 	 * 	#else
    261 	 * 		return SSP_READ(sc, STATUS) & CARD_DETECT;
    262 	 * 	#endif
    263 	 * Until GPIO functionality is not present I am just going to */
    264 
    265 	return 1;
    266 }
    267 
    268 static int
    269 issp_write_protect(sdmmc_chipset_handle_t sch)
    270 {
    271 	/* The device is not write protected. */
    272 	return 0;
    273 }
    274 
    275 static int
    276 issp_bus_power(sdmmc_chipset_handle_t sch, uint32_t power)
    277 {
    278 	/* i.MX233 does not support setting bus power. */
    279 	return 0;
    280 }
    281 
    282 static int
    283 issp_bus_clock(sdmmc_chipset_handle_t sch, int clock)
    284 {
    285 	struct issp_softc *sc = sch;
    286 	uint32_t sck;
    287 
    288 	aprint_normal_dev(sc->sc_dev, "requested clock %d Hz", clock * 1000);
    289 	sck = issp_set_sck(sc, clock * 1000);
    290 	aprint_normal(", got %d Hz\n", sck);
    291 
    292 	return 0;
    293 }
    294 
    295 static int
    296 issp_bus_width(sdmmc_chipset_handle_t sch, int width)
    297 {
    298 	/* Return error if other than 4-bit width is requested. */
    299 	return width - 4;
    300 }
    301 
    302 static int
    303 issp_bus_rod(sdmmc_chipset_handle_t sch, int rod)
    304 {
    305 	/* Go to data transfer mode. */
    306 	return 0;
    307 }
    308 
    309 static void
    310 issp_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
    311 {
    312 	struct issp_softc *sc = sch;
    313 	uint32_t reg;
    314 
    315 	/* Set excepted response type. */
    316 	SSP_WRITE(sc, HW_SSP_CTRL0_CLR,
    317 	    HW_SSP_CTRL0_GET_RESP | HW_SSP_CTRL0_LONG_RESP);
    318 
    319 	if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
    320 		SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_GET_RESP);
    321 		if (ISSET(cmd->c_flags, SCF_RSP_136))
    322 			SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_LONG_RESP);
    323 	}
    324 
    325 	/* If CMD does not need CRC validation, tell it to SSP. */
    326 	if (ISSET(cmd->c_flags, SCF_RSP_CRC))
    327 		SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_IGNORE_CRC);
    328 	else
    329 		SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_IGNORE_CRC);
    330 
    331 	/* Set command. */
    332 	SSP_WRITE(sc, HW_SSP_CMD0_CLR, HW_SSP_CMD0_CMD);
    333 	SSP_WRITE(sc, HW_SSP_CMD0_SET,
    334 	    __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD));
    335 
    336 	/* Set command argument. */
    337 	SSP_WRITE(sc, HW_SSP_CMD1, cmd->c_arg);
    338 
    339 	/* Run the command. */
    340 	SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_RUN);
    341 
    342 	/* Wait until SSP has processed the command. */
    343 	while (SSP_READ(sc, HW_SSP_STATUS) &
    344 	    (HW_SSP_STATUS_CMD_BUSY | HW_SSP_STATUS_BUSY))
    345 			;
    346 
    347 	/* Check if the command ran without errors. */
    348 	reg = SSP_READ(sc, HW_SSP_STATUS);
    349 
    350 	if (reg & SSP_STATUS_ERR)
    351 		cmd->c_error = reg & SSP_STATUS_ERR;
    352 
    353 	/* Read response if such was requested. */
    354 	if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
    355 		cmd->c_resp[0] = SSP_READ(sc, HW_SSP_SDRESP0);
    356 		if (ISSET(cmd->c_flags, SCF_RSP_136)) {
    357 		    cmd->c_resp[1] = SSP_READ(sc, HW_SSP_SDRESP1);
    358 		    cmd->c_resp[2] = SSP_READ(sc, HW_SSP_SDRESP2);
    359 		    cmd->c_resp[3] = SSP_READ(sc, HW_SSP_SDRESP3);
    360 		}
    361 	}
    362 
    363 /*
    364 	apbdma_dmamem_alloc()
    365 	apbdma_do_dma()
    366 	wait_until_done()
    367 */
    368 	return;
    369 }
    370 
    371 static void
    372 issp_card_enable_intr(sdmmc_chipset_handle_t sch, int irq)
    373 {
    374 	struct issp_softc *sc = sch;
    375 
    376 	aprint_normal_dev(sc->sc_dev,
    377 		"issp_card_enable_intr NOT IMPLEMENTED!\n");
    378 
    379 	return;
    380 }
    381 
    382 static void
    383 issp_card_intr_ack(sdmmc_chipset_handle_t sch)
    384 {
    385 	struct issp_softc *sc = sch;
    386 
    387 	aprint_normal_dev(sc->sc_dev, "issp_card_intr_ack NOT IMPLEMENTED!\n");
    388 
    389 	return;
    390 }
    391 
    392 /*
    393  * Reset the SSP block.
    394  *
    395  * Inspired by i.MX233 RM "39.3.10 Correct Way to Soft Reset a Block"
    396  */
    397 static void
    398 issp_reset(struct issp_softc *sc)
    399 {
    400 	unsigned int loop;
    401 
    402 	/* Prepare for soft-reset by making sure that SFTRST is not currently
    403 	 * asserted. Also clear CLKGATE so we can wait for its assertion below.
    404 	 */
    405 	SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
    406 
    407 	/* Wait at least a microsecond for SFTRST to deassert. */
    408 	loop = 0;
    409 	while ((SSP_READ(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
    410 	    (loop < SSP_SOFT_RST_LOOP))
    411 		loop++;
    412 
    413 	/* Clear CLKGATE so we can wait for its assertion below. */
    414 	SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
    415 
    416 	/* Soft-reset the block. */
    417 	SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_SFTRST);
    418 
    419 	/* Wait until clock is in the gated state. */
    420 	while (!(SSP_READ(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE));
    421 
    422 	/* Bring block out of reset. */
    423 	SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
    424 
    425 	loop = 0;
    426 	while ((SSP_READ(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
    427 	    (loop < SSP_SOFT_RST_LOOP))
    428 		loop++;
    429 
    430 	SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
    431 
    432 	/* Wait until clock is in the NON-gated state. */
    433 	while (SSP_READ(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE);
    434 
    435 	return;
    436 }
    437 
    438 /*
    439  * Initialize common options.
    440  */
    441 static void
    442 issp_init(struct issp_softc *sc)
    443 {
    444 	uint32_t reg;
    445 
    446 	/* Initialize SD/MMC controller. */
    447 	reg = SSP_READ(sc, HW_SSP_CTRL0);
    448 	reg &= ~(HW_SSP_CTRL0_BUS_WIDTH);
    449 	reg |= __SHIFTIN(0x1, HW_SSP_CTRL0_BUS_WIDTH) | HW_SSP_CTRL0_ENABLE;
    450 	SSP_WRITE(sc, HW_SSP_CTRL0, reg);
    451 
    452 	reg = SSP_READ(sc, HW_SSP_CTRL1);
    453 	reg &= ~(HW_SSP_CTRL1_WORD_LENGTH | HW_SSP_CTRL1_SSP_MODE);
    454 	reg |= HW_SSP_CTRL1_POLARITY |
    455 	    __SHIFTIN(0x7, HW_SSP_CTRL1_WORD_LENGTH) |
    456 	    __SHIFTIN(0x3, HW_SSP_CTRL1_SSP_MODE);
    457 	SSP_WRITE(sc, HW_SSP_CTRL1, reg);
    458 
    459 	/* Set command timeout. */
    460 	reg = SSP_READ(sc, HW_SSP_TIMING);
    461 	reg &= ~(HW_SSP_TIMING_TIMEOUT);
    462 	reg |= __SHIFTIN(SSP_CMD_TIMEOUT, HW_SSP_TIMING_TIMEOUT);
    463 	SSP_WRITE(sc, HW_SSP_TIMING, reg);
    464 
    465 	return;
    466 }
    467 
    468 /*
    469  * Set SSP_SCK clock rate to the value specified in target.
    470  *
    471  * SSP_SCK is calculated as: SSP_CLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE))
    472  *
    473  * issp_set_sck find the most suitable CLOCK_DIVIDE and CLOCK_RATE register
    474  * values for the target clock rate by iterating through all possible register
    475  * values.
    476  */
    477 static uint32_t
    478 issp_set_sck(struct issp_softc *sc, uint32_t target)
    479 {
    480 	uint32_t newclk, found, reg;
    481 	uint8_t div, rate, d, r;
    482 
    483 	found = div = rate = 0;
    484 
    485 	for (d = 2; d < 254; d++) {
    486 		for (r = 0; r < 255; r++) {
    487 			newclk = SSP_CLK / (d * (1 + r));
    488 			if (newclk == target) {
    489 				found = newclk;
    490 				div = d;
    491 				rate = r;
    492 				goto out;
    493 			}
    494 			if (newclk < target && newclk > found) {
    495 				found = newclk;
    496 				div = d;
    497 				rate = r;
    498 			}
    499 		}
    500 	}
    501 out:
    502 	reg = SSP_READ(sc, HW_SSP_TIMING);
    503 	reg &= ~(HW_SSP_TIMING_CLOCK_DIVIDE | HW_SSP_TIMING_CLOCK_RATE);
    504 	reg |= __SHIFTIN(div, HW_SSP_TIMING_CLOCK_DIVIDE) |
    505 	    __SHIFTIN(rate, HW_SSP_TIMING_CLOCK_RATE);
    506 	SSP_WRITE(sc, HW_SSP_TIMING, reg);
    507 
    508 	return SSP_CLK / (d * (1 + r));
    509 }
    510