imx23_mmc.c revision 1.4
1/* $NetBSD: imx23_mmc.c,v 1.4 2026/02/02 09:21:30 yurix 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/condvar.h>
37#include <sys/device.h>
38#include <sys/errno.h>
39#include <sys/mutex.h>
40#include <sys/systm.h>
41
42#include <dev/fdt/fdtvar.h>
43#include <dev/sdmmc/sdmmcchip.h>
44#include <dev/sdmmc/sdmmcreg.h>
45#include <dev/sdmmc/sdmmcvar.h>
46
47#include <arm/imx/imx23_icollreg.h>
48#include <arm/imx/imx23_mmcreg.h>
49#include <arm/imx/imx23var.h>
50#include <arm/pic/picvar.h>
51
52/*
53 * SD/MMC host controller driver for i.MX23.
54 *
55 * TODO:
56 *
57 * - Add support for SMC_CAPS_AUTO_STOP.
58 * - Uset GPIO for SD card detection.
59 */
60
61struct imx23_mmc_softc {
62	device_t sc_dev;
63	struct fdtbus_dma *dma_channel;
64	bus_space_handle_t sc_hdl;
65	bus_space_tag_t sc_iot;
66	device_t sc_sdmmc;
67	kmutex_t sc_lock;
68	struct kcondvar sc_intr_cv;
69	uint32_t sc_irq_error;
70	uint8_t sc_state;
71	uint8_t sc_bus_width;
72	uint32_t pio_words[3];
73};
74
75
76static int	imx23_mmc_match(device_t, cfdata_t, void *);
77static void	imx23_mmc_attach(device_t, device_t, void *);
78
79static void	imx23_mmc_reset(struct imx23_mmc_softc *);
80static void	imx23_mmc_init(struct imx23_mmc_softc *);
81static uint32_t	imx23_mmc_set_sck(struct imx23_mmc_softc *, uint32_t);
82static void	imx23_mmc_dma_intr(void *);
83static int	imx23_mmc_error_intr(void *);
84static void 	imx23_mmc_prepare_data_command(struct imx23_mmc_softc *,
85			       struct fdtbus_dma_req *, struct sdmmc_command *);
86static void 	imx23_mmc_prepare_command(struct imx23_mmc_softc *,
87			  struct fdtbus_dma_req *, struct sdmmc_command *);
88
89/* sdmmc(4) driver chip function prototypes. */
90static int	imx23_mmc_host_reset(sdmmc_chipset_handle_t);
91static uint32_t	imx23_mmc_host_ocr(sdmmc_chipset_handle_t);
92static int	imx23_mmc_host_maxblklen(sdmmc_chipset_handle_t);
93static int	imx23_mmc_card_detect(sdmmc_chipset_handle_t);
94static int	imx23_mmc_write_protect(sdmmc_chipset_handle_t);
95static int	imx23_mmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
96static int	imx23_mmc_bus_clock(sdmmc_chipset_handle_t, int);
97static int	imx23_mmc_bus_width(sdmmc_chipset_handle_t, int);
98static int	imx23_mmc_bus_rod(sdmmc_chipset_handle_t, int);
99static void	imx23_mmc_exec_command(sdmmc_chipset_handle_t,
100		struct sdmmc_command *);
101static void	imx23_mmc_card_enable_intr(sdmmc_chipset_handle_t, int);
102static void	imx23_mmc_card_intr_ack(sdmmc_chipset_handle_t);
103
104static struct sdmmc_chip_functions imx23_mmc_functions = {
105	.host_reset	= imx23_mmc_host_reset,
106	.host_ocr	= imx23_mmc_host_ocr,
107	.host_maxblklen	= imx23_mmc_host_maxblklen,
108	.card_detect	= imx23_mmc_card_detect,
109	.write_protect	= imx23_mmc_write_protect,
110	.bus_power	= imx23_mmc_bus_power,
111	.bus_clock	= imx23_mmc_bus_clock,
112	.bus_width	= imx23_mmc_bus_width,
113	.bus_rod	= imx23_mmc_bus_rod,
114	.exec_command	= imx23_mmc_exec_command,
115	.card_enable_intr = imx23_mmc_card_enable_intr,
116	.card_intr_ack	= imx23_mmc_card_intr_ack
117};
118
119CFATTACH_DECL_NEW(imx23mmc, sizeof(struct imx23_mmc_softc), imx23_mmc_match,
120		  imx23_mmc_attach, NULL, NULL);
121
122#define SSP_SOFT_RST_LOOP 455	/* At least 1 us ... */
123
124#define SSP_RD(sc, reg)							\
125	bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
126#define SSP_WR(sc, reg, val)						\
127	bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
128
129#define SSP_CLK		160000000	/* CLK_SSP from PLL in Hz */
130#define SSP_CLK_MIN	400		/* 400 kHz */
131#define SSP_CLK_MAX	48000		/* 48 MHz */
132
133/* DATA_TIMEOUT is calculated as: * (1 / SSP_CLK) * (DATA_TIMEOUT * 4096) */
134#define DATA_TIMEOUT 0x4240
135
136#define BUS_WIDTH_1_BIT 0x0
137#define BUS_WIDTH_4_BIT 0x1
138#define BUS_WIDTH_8_BIT 0x2
139
140/* Flags for sc_state. */
141#define SSP_STATE_IDLE	0
142#define SSP_STATE_DMA	1
143
144#define HW_SSP_CTRL1_IRQ_MASK (						\
145    HW_SSP_CTRL1_SDIO_IRQ |						\
146    HW_SSP_CTRL1_RESP_ERR_IRQ |						\
147    HW_SSP_CTRL1_RESP_TIMEOUT_IRQ |					\
148    HW_SSP_CTRL1_DATA_TIMEOUT_IRQ |					\
149    HW_SSP_CTRL1_DATA_CRC_IRQ |						\
150    HW_SSP_CTRL1_FIFO_UNDERRUN_IRQ |					\
151    HW_SSP_CTRL1_RECV_TIMEOUT_IRQ |					\
152    HW_SSP_CTRL1_FIFO_OVERRUN_IRQ)
153
154/* SSP does not support over 64k transfer size. */
155#define MAX_TRANSFER_SIZE 65536
156
157/* Offsets of pio words in pio array */
158#define PIO_WORD_CTRL0	0
159#define PIO_WORD_CMD0	1
160#define PIO_WORD_CMD1	2
161
162static const struct device_compatible_entry compat_data[] = {
163	{ .compat = "fsl,imx23-mmc" },
164	DEVICE_COMPAT_EOL
165};
166
167static int
168imx23_mmc_match(device_t parent, cfdata_t match, void *aux)
169{
170	struct fdt_attach_args *const faa = aux;
171
172	return of_compatible_match(faa->faa_phandle, compat_data);
173}
174
175static void
176imx23_mmc_attach(device_t parent, device_t self, void *aux)
177{
178	struct imx23_mmc_softc *const sc = device_private(self);
179	struct fdt_attach_args *const faa = aux;
180	const int phandle = faa->faa_phandle;
181	struct sdmmcbus_attach_args saa;
182	char intrstr[128];
183
184	sc->sc_dev = self;
185	sc->sc_iot = faa->faa_bst;
186
187	/* map ssp control registers */
188	bus_addr_t addr;
189	bus_size_t size;
190	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
191		aprint_error(": couldn't get register address\n");
192		return;
193	}
194	if (bus_space_map(faa->faa_bst, addr, size, 0, &sc->sc_hdl)) {
195		aprint_error(": couldn't map registers\n");
196		return;
197	}
198
199	/* Initialize lock. */
200	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SCHED);
201
202	/* Condvar to wait interrupt complete. */
203	cv_init(&sc->sc_intr_cv, "ssp_intr");
204
205	/* acquire DMA channel */
206	sc->dma_channel = fdtbus_dma_get(phandle,"rx-tx", imx23_mmc_dma_intr,
207					 sc);
208	if(sc->dma_channel == NULL) {
209		aprint_error(": couldn't map registers\n");
210		return;
211	}
212
213	/* establish error interrupt */
214	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
215		aprint_error(": failed to decode interrupt\n");
216		return;
217	}
218	void *ih = fdtbus_intr_establish_xname(phandle, 0, IPL_SDMMC, IST_LEVEL,
219					       imx23_mmc_error_intr, sc,
220					 device_xname(self));
221	if (ih == NULL) {
222		aprint_error_dev(self, "couldn't establish error interrupt\n");
223		return;
224	}
225
226	imx23_mmc_reset(sc);
227	imx23_mmc_init(sc);
228
229	uint32_t imx23_mmc_vers = SSP_RD(sc, HW_SSP_VERSION);
230	aprint_normal(": SSP Block v%" __PRIuBIT ".%" __PRIuBIT "\n",
231	    __SHIFTOUT(imx23_mmc_vers, HW_SSP_VERSION_MAJOR),
232	    __SHIFTOUT(imx23_mmc_vers, HW_SSP_VERSION_MINOR));
233
234	/* Attach sdmmc to ssp bus. */
235	memset(&saa, 0, sizeof(saa));
236	saa.saa_busname = "sdmmc";
237	saa.saa_sct	= &imx23_mmc_functions;
238	saa.saa_spi_sct	= NULL;
239	saa.saa_sch	= sc;
240	saa.saa_dmat	= faa->faa_dmat;
241	saa.saa_clkmin	= SSP_CLK_MIN;
242	saa.saa_clkmax	= SSP_CLK_MAX;
243	saa.saa_caps	= SMC_CAPS_DMA | SMC_CAPS_4BIT_MODE;
244
245	sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL, CFARGS_NONE);
246	if (sc->sc_sdmmc == NULL) {
247		aprint_error_dev(sc->sc_dev, "unable to attach sdmmc\n");
248		return;
249	}
250}
251
252/*
253 * sdmmc chip functions.
254 */
255static int
256imx23_mmc_host_reset(sdmmc_chipset_handle_t sch)
257{
258	struct imx23_mmc_softc *sc = sch;
259	imx23_mmc_reset(sc);
260	return 0;
261}
262
263static uint32_t
264imx23_mmc_host_ocr(sdmmc_chipset_handle_t sch)
265{
266	/* SSP supports at least 3.2 - 3.3v */
267	return MMC_OCR_3_2V_3_3V;
268}
269
270static int
271imx23_mmc_host_maxblklen(sdmmc_chipset_handle_t sch)
272{
273	return 512;
274}
275
276/*
277 * Called at the beginning of sdmmc_task_thread to detect the presence
278 * of the SD card.
279 */
280static int
281imx23_mmc_card_detect(sdmmc_chipset_handle_t sch)
282{
283	return 1; /* the olinuxino has no card detection */
284}
285
286static int
287imx23_mmc_write_protect(sdmmc_chipset_handle_t sch)
288{
289	/* The device is not write protected. */
290	return 0;
291}
292
293static int
294imx23_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
295{
296	/* i.MX23 SSP does not support setting bus power. */
297	return 0;
298}
299
300static int
301imx23_mmc_bus_clock(sdmmc_chipset_handle_t sch, int clock)
302{
303	struct imx23_mmc_softc *sc = sch;
304	uint32_t sck;
305
306	if (clock < SSP_CLK_MIN)
307		sck = imx23_mmc_set_sck(sc, SSP_CLK_MIN * 1000);
308	else
309		sck = imx23_mmc_set_sck(sc, clock * 1000);
310
311	/* Notify user if we didn't get the exact clock rate from SSP that was
312	 * requested from the SDMMC subsystem. */
313	if (sck != clock * 1000) {
314		sck = sck / 1000;
315		if (((sck) / 1000) != 0)
316			aprint_normal_dev(sc->sc_dev, "bus clock @ %u.%03u "
317			    "MHz\n", sck / 1000, sck % 1000);
318		else
319			aprint_normal_dev(sc->sc_dev, "bus clock @ %u KHz\n",
320			    sck % 1000);
321	}
322
323	return 0;
324}
325
326static int
327imx23_mmc_bus_width(sdmmc_chipset_handle_t sch, int width)
328{
329	struct imx23_mmc_softc *sc = sch;
330
331	switch(width) {
332	case(1):
333		sc->sc_bus_width = BUS_WIDTH_1_BIT;
334		break;
335	case(4):
336		sc->sc_bus_width = BUS_WIDTH_4_BIT;
337		break;
338	case(8):
339		sc->sc_bus_width = BUS_WIDTH_8_BIT;
340		break;
341	default:
342		return 1;
343	}
344
345	return 0;
346}
347
348static int
349imx23_mmc_bus_rod(sdmmc_chipset_handle_t sch, int rod)
350{
351	/* Go to data transfer mode. */
352	return 0;
353}
354
355static void
356imx23_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
357{
358	struct imx23_mmc_softc *sc = sch;
359	struct fdtbus_dma_req req;
360
361	/* SSP does not support over 64k transfer size. */
362	if (cmd->c_data != NULL && cmd->c_datalen > MAX_TRANSFER_SIZE) {
363		aprint_error_dev(sc->sc_dev, "transfer size over %d: %d\n",
364		    MAX_TRANSFER_SIZE, cmd->c_datalen);
365		cmd->c_error = ENODEV;
366		return;
367	}
368
369	mutex_enter(&sc->sc_lock);
370
371	/* Setup DMA command chain.*/
372	if (cmd->c_data != NULL && cmd->c_datalen) {
373		/* command with data */
374		imx23_mmc_prepare_data_command(sc, &req, cmd);
375	} else {
376		/* Only command, no data. */
377		imx23_mmc_prepare_command(sc, &req, cmd);
378	}
379
380
381	sc->sc_state = SSP_STATE_DMA;
382	sc->sc_irq_error = 0;
383	cmd->c_error = 0;
384
385	/* Run DMA */
386	if(fdtbus_dma_transfer(sc->dma_channel, &req)) {
387		aprint_error_dev(sc->sc_dev, "dma transfer error\n");
388		goto out;
389	}
390
391	/* Wait DMA to complete. */
392	while (sc->sc_state == SSP_STATE_DMA)
393		cv_wait(&sc->sc_intr_cv, &sc->sc_lock);
394
395	if (sc->sc_irq_error) {
396		/* Do not log RESP_TIMEOUT_IRQ error if bus width is 0 as it is
397		 * expected during SD card initialization phase. */
398		if (sc->sc_bus_width) {
399			aprint_error_dev(sc->sc_dev, "SSP_ERROR_IRQ: %d\n",
400			    sc->sc_irq_error);
401		}
402		else if(!(sc->sc_irq_error & HW_SSP_CTRL1_RESP_TIMEOUT_IRQ)) {
403			aprint_error_dev(sc->sc_dev, "SSP_ERROR_IRQ: %d\n",
404			    sc->sc_irq_error);
405		}
406
407		/* Shift unsigned error code so it fits nicely to signed int. */
408		cmd->c_error = sc->sc_irq_error >> 8;
409	}
410
411	/* Check response from the card if such was requested. */
412	if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
413		cmd->c_resp[0] = SSP_RD(sc, HW_SSP_SDRESP0);
414		if (ISSET(cmd->c_flags, SCF_RSP_136)) {
415			cmd->c_resp[1] = SSP_RD(sc, HW_SSP_SDRESP1);
416			cmd->c_resp[2] = SSP_RD(sc, HW_SSP_SDRESP2);
417			cmd->c_resp[3] = SSP_RD(sc, HW_SSP_SDRESP3);
418			/*
419			 * Remove CRC7 + LSB by rotating all bits right by 8 to
420			 * make sdmmc __bitfield() happy.
421			 */
422			cmd->c_resp[0] >>= 8; /* Remove CRC7 + LSB. */
423			cmd->c_resp[0] |= (0x000000FF & cmd->c_resp[1]) << 24;
424			cmd->c_resp[1] >>= 8;
425			cmd->c_resp[1] |= (0x000000FF & cmd->c_resp[2]) << 24;
426			cmd->c_resp[2] >>= 8;
427			cmd->c_resp[2] |= (0x000000FF & cmd->c_resp[3]) << 24;
428			cmd->c_resp[3] >>= 8;
429		}
430	}
431
432out:
433	mutex_exit(&sc->sc_lock);
434}
435
436static void
437imx23_mmc_card_enable_intr(sdmmc_chipset_handle_t sch, int irq)
438{
439	struct imx23_mmc_softc *sc = sch;
440	aprint_error_dev(sc->sc_dev, "issp_card_enable_intr not implemented\n");
441	return;
442}
443
444static void
445imx23_mmc_card_intr_ack(sdmmc_chipset_handle_t sch)
446{
447	struct imx23_mmc_softc *sc = sch;
448	aprint_error_dev(sc->sc_dev, "issp_card_intr_ack not implemented\n");
449}
450
451/*
452 * Reset the SSP block.
453 *
454 * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
455 */
456static void
457imx23_mmc_reset(struct imx23_mmc_softc *sc)
458{
459	unsigned int loop;
460
461	/* Prepare for soft-reset by making sure that SFTRST is not currently
462	 * asserted. Also clear CLKGATE so we can wait for its assertion below.
463	 */
464	SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
465
466	/* Wait at least a microsecond for SFTRST to deassert. */
467	loop = 0;
468	while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
469	    (loop < SSP_SOFT_RST_LOOP))
470		loop++;
471
472	/* Clear CLKGATE so we can wait for its assertion below. */
473	SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
474
475	/* Soft-reset the block. */
476	SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_SFTRST);
477
478	/* Wait until clock is in the gated state. */
479	while (!(SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE));
480
481	/* Bring block out of reset. */
482	SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
483
484	loop = 0;
485	while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
486	    (loop < SSP_SOFT_RST_LOOP))
487		loop++;
488
489	SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
490
491	/* Wait until clock is in the NON-gated state. */
492	while (SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE);
493
494	return;
495}
496
497/*
498 * Initialize SSP controller to SD/MMC mode.
499 */
500static void
501imx23_mmc_init(struct imx23_mmc_softc *sc)
502{
503	uint32_t reg;
504
505	reg = SSP_RD(sc, HW_SSP_CTRL0);
506	reg |= HW_SSP_CTRL0_ENABLE;
507
508	/* Initial data bus width is 1-bit. */
509	reg &= ~(HW_SSP_CTRL0_BUS_WIDTH);
510	reg |= __SHIFTIN(BUS_WIDTH_1_BIT, HW_SSP_CTRL0_BUS_WIDTH) |
511	    HW_SSP_CTRL0_WAIT_FOR_IRQ | HW_SSP_CTRL0_ENABLE;
512	SSP_WR(sc, HW_SSP_CTRL0, reg);
513	sc->sc_bus_width = BUS_WIDTH_1_BIT;
514
515	/* Set data timeout. */
516	reg = SSP_RD(sc, HW_SSP_TIMING);
517	reg &= ~(HW_SSP_TIMING_TIMEOUT);
518	reg |= __SHIFTIN(DATA_TIMEOUT, HW_SSP_TIMING_TIMEOUT);
519	SSP_WR(sc, HW_SSP_TIMING, reg);
520
521	/* Set initial clock rate to minimum. */
522	imx23_mmc_set_sck(sc, SSP_CLK_MIN * 1000);
523
524	reg = SSP_RD(sc, HW_SSP_CTRL1);
525	/* Enable all but SDIO IRQ's. */
526	reg |= HW_SSP_CTRL1_RESP_ERR_IRQ_EN |
527	    HW_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN |
528	    HW_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN |
529	    HW_SSP_CTRL1_DATA_CRC_IRQ_EN |
530	    HW_SSP_CTRL1_FIFO_UNDERRUN_EN |
531	    HW_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN |
532	    HW_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN;
533	reg |= HW_SSP_CTRL1_DMA_ENABLE;
534	reg |= HW_SSP_CTRL1_POLARITY;
535	/* Set SD/MMC mode and use use 8-bits per word. */
536	reg &= ~(HW_SSP_CTRL1_WORD_LENGTH | HW_SSP_CTRL1_SSP_MODE);
537	reg |= __SHIFTIN(0x7, HW_SSP_CTRL1_WORD_LENGTH) |
538	    __SHIFTIN(0x3, HW_SSP_CTRL1_SSP_MODE);
539	SSP_WR(sc, HW_SSP_CTRL1, reg);
540}
541
542/*
543 * Set SSP_SCK clock rate to the value specified in target.
544 *
545 * SSP_SCK is calculated as: SSP_CLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE))
546 *
547 * imx23_mmc_set_sck finds the most suitable CLOCK_DIVIDE and CLOCK_RATE
548 * register values for the target clock rate by iterating through all possible
549 * register values.
550 */
551static uint32_t
552imx23_mmc_set_sck(struct imx23_mmc_softc *sc, uint32_t target)
553{
554	uint32_t newclk, found, reg;
555	uint8_t div, rate, d, r;
556
557	found = div = rate = 0;
558
559	for (d = 2; d < 254; d++) {
560		for (r = 0; r < 255; r++) {
561			newclk = SSP_CLK / (d * (1 + r));
562			if (newclk == target) {
563				found = newclk;
564				div = d;
565				rate = r;
566				goto out;
567			}
568			if (newclk < target && newclk > found) {
569				found = newclk;
570				div = d;
571				rate = r;
572			}
573		}
574	}
575out:
576	reg = SSP_RD(sc, HW_SSP_TIMING);
577	reg &= ~(HW_SSP_TIMING_CLOCK_DIVIDE | HW_SSP_TIMING_CLOCK_RATE);
578	reg |= __SHIFTIN(div, HW_SSP_TIMING_CLOCK_DIVIDE) |
579	    __SHIFTIN(rate, HW_SSP_TIMING_CLOCK_RATE);
580	SSP_WR(sc, HW_SSP_TIMING, reg);
581
582	return SSP_CLK / (div * (1 + rate));
583}
584
585/*
586 * IRQ from DMA.
587 */
588static void
589imx23_mmc_dma_intr(void *arg)
590{
591	struct imx23_mmc_softc *sc = arg;
592
593	mutex_enter(&sc->sc_lock);
594
595	sc->sc_state = SSP_STATE_IDLE;
596
597	/* Signal thread that interrupt was handled. */
598	cv_signal(&sc->sc_intr_cv);
599
600	mutex_exit(&sc->sc_lock);
601}
602
603/*
604 * IRQ from SSP block.
605 *
606 * When SSP receives IRQ it terminates ongoing DMA transfer by issuing DMATERM
607 * signal to DMA block.
608 */
609static int
610imx23_mmc_error_intr(void *arg)
611{
612	struct imx23_mmc_softc *sc = arg;
613
614	mutex_enter(&sc->sc_lock);
615
616	sc->sc_irq_error =
617	    SSP_RD(sc, HW_SSP_CTRL1) & HW_SSP_CTRL1_IRQ_MASK;
618
619	/* Acknowledge all IRQ's. */
620	SSP_WR(sc, HW_SSP_CTRL1_CLR, HW_SSP_CTRL1_IRQ_MASK);
621
622	mutex_exit(&sc->sc_lock);
623
624	/* Return 1 to acknowledge IRQ. */
625	return 1;
626}
627
628/*
629 * Set up a dma transfer for a block with data.
630 */
631static void
632imx23_mmc_prepare_data_command(struct imx23_mmc_softc *sc,
633	struct fdtbus_dma_req *req, struct sdmmc_command *cmd)
634{
635	int block_count = cmd->c_datalen / cmd->c_blklen;
636
637	/* prepare DMA request */
638	req->dreq_segs = cmd->c_dmamap->dm_segs;
639	req->dreq_nsegs = cmd->c_dmamap->dm_nsegs;
640	req->dreq_block_irq = 1;
641	req->dreq_block_multi = 0;
642	req->dreq_datalen = 3;
643	req->dreq_data = sc->pio_words;
644
645	/* prepare CTRL0 register*/
646	sc->pio_words[PIO_WORD_CTRL0] =
647	    HW_SSP_CTRL0_DATA_XFER |
648	    __SHIFTIN(sc->sc_bus_width, HW_SSP_CTRL0_BUS_WIDTH) |
649	    HW_SSP_CTRL0_WAIT_FOR_IRQ |
650	    __SHIFTIN(cmd->c_datalen, HW_SSP_CTRL0_XFER_COUNT) |
651	    HW_SSP_CTRL0_ENABLE;
652	if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
653		req->dreq_dir = FDT_DMA_READ;
654		sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_READ;
655	} else {
656		req->dreq_dir = FDT_DMA_WRITE;
657	}
658	if (!ISSET(cmd->c_flags, SCF_RSP_CRC)) {
659		sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_IGNORE_CRC;
660	}
661	if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
662		sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_GET_RESP;
663		if (ISSET(cmd->c_flags, SCF_RSP_136)) {
664			sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_LONG_RESP;
665		}
666	}
667
668	/* prepare CMD0 register */
669	sc->pio_words[PIO_WORD_CMD0] =
670	    HW_SSP_CMD0_APPEND_8CYC |
671	    __SHIFTIN(ffs(cmd->c_blklen) - 1, HW_SSP_CMD0_BLOCK_SIZE) |
672	    __SHIFTIN(block_count - 1, HW_SSP_CMD0_BLOCK_COUNT) |
673	    __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD);
674
675	/* prepare CMD1 register */
676	sc->pio_words[PIO_WORD_CMD1] = cmd->c_arg;
677}
678
679/*
680 * Setup a dma transfer for a command without data (PIO only)
681 */
682static void
683imx23_mmc_prepare_command(struct imx23_mmc_softc *sc,
684	struct fdtbus_dma_req *req, struct sdmmc_command *cmd)
685{
686	/* prepare DMA */
687	req->dreq_nsegs = 0;
688	req->dreq_block_irq = 1;
689	req->dreq_block_multi = 0;
690	req->dreq_dir = FDT_DMA_NO_XFER;
691	req->dreq_datalen = 3;
692	req->dreq_data = sc->pio_words;
693
694	/* prepare CTRL0 register*/
695	sc->pio_words[PIO_WORD_CTRL0] =
696	    __SHIFTIN(sc->sc_bus_width, HW_SSP_CTRL0_BUS_WIDTH) |
697	    HW_SSP_CTRL0_WAIT_FOR_IRQ | HW_SSP_CTRL0_ENABLE;
698	if (!ISSET(cmd->c_flags, SCF_RSP_CRC)) {
699		sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_IGNORE_CRC;
700	}
701	if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
702		sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_GET_RESP;
703		if (ISSET(cmd->c_flags, SCF_RSP_136)) {
704			sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_LONG_RESP;
705		}
706	}
707
708	/* prepare CMD0 register */
709	sc->pio_words[PIO_WORD_CMD0] =
710	    __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD);
711
712	/* prepare CMD1 register */
713	sc->pio_words[PIO_WORD_CMD1] = cmd->c_arg;
714}
715