imx23_ssp.c revision 1.3 1 1.3 jkunz /* $Id: imx23_ssp.c,v 1.3 2013/03/03 10:33:56 jkunz Exp $ */
2 1.1 jkunz
3 1.1 jkunz /*
4 1.1 jkunz * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 1.1 jkunz * All rights reserved.
6 1.1 jkunz *
7 1.1 jkunz * This code is derived from software contributed to The NetBSD Foundation
8 1.1 jkunz * by Petri Laakso.
9 1.1 jkunz *
10 1.1 jkunz * Redistribution and use in source and binary forms, with or without
11 1.1 jkunz * modification, are permitted provided that the following conditions
12 1.1 jkunz * are met:
13 1.1 jkunz * 1. Redistributions of source code must retain the above copyright
14 1.1 jkunz * notice, this list of conditions and the following disclaimer.
15 1.1 jkunz * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 jkunz * notice, this list of conditions and the following disclaimer in the
17 1.1 jkunz * documentation and/or other materials provided with the distribution.
18 1.1 jkunz *
19 1.1 jkunz * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 jkunz * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 jkunz * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 jkunz * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 jkunz * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 jkunz * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 jkunz * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 jkunz * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 jkunz * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 jkunz * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 jkunz * POSSIBILITY OF SUCH DAMAGE.
30 1.1 jkunz */
31 1.1 jkunz
32 1.1 jkunz #include <sys/param.h>
33 1.1 jkunz #include <sys/types.h>
34 1.1 jkunz #include <sys/bus.h>
35 1.1 jkunz #include <sys/cdefs.h>
36 1.3 jkunz #include <sys/condvar.h>
37 1.1 jkunz #include <sys/device.h>
38 1.1 jkunz #include <sys/errno.h>
39 1.3 jkunz #include <sys/mutex.h>
40 1.1 jkunz #include <sys/systm.h>
41 1.1 jkunz
42 1.3 jkunz #include <arm/pic/picvar.h>
43 1.3 jkunz
44 1.3 jkunz #include <arm/imx/imx23_apbdmavar.h>
45 1.3 jkunz #include <arm/imx/imx23_icollreg.h>
46 1.1 jkunz #include <arm/imx/imx23_sspreg.h>
47 1.1 jkunz #include <arm/imx/imx23var.h>
48 1.1 jkunz
49 1.1 jkunz #include <dev/sdmmc/sdmmcchip.h>
50 1.1 jkunz #include <dev/sdmmc/sdmmcreg.h>
51 1.1 jkunz #include <dev/sdmmc/sdmmcvar.h>
52 1.1 jkunz
53 1.1 jkunz /*
54 1.2 jkunz * SD/MMC host controller driver for i.MX23.
55 1.3 jkunz *
56 1.3 jkunz * TODO:
57 1.3 jkunz *
58 1.3 jkunz * - Add support for SMC_CAPS_AUTO_STOP.
59 1.1 jkunz */
60 1.1 jkunz
61 1.3 jkunz #define DMA_MAXNSEGS ((MAXPHYS / PAGE_SIZE) + 1)
62 1.3 jkunz
63 1.3 jkunz typedef struct issp_softc {
64 1.1 jkunz device_t sc_dev;
65 1.3 jkunz apbdma_softc_t sc_dmac;
66 1.3 jkunz bus_dma_tag_t sc_dmat;
67 1.3 jkunz bus_dmamap_t sc_dmamp;
68 1.3 jkunz bus_size_t sc_chnsiz;
69 1.3 jkunz bus_dma_segment_t sc_ds[1];
70 1.3 jkunz int sc_rseg;
71 1.3 jkunz bus_space_handle_t sc_hdl;
72 1.1 jkunz bus_space_tag_t sc_iot;
73 1.1 jkunz device_t sc_sdmmc;
74 1.3 jkunz kmutex_t sc_lock;
75 1.3 jkunz struct kcondvar sc_intr_cv;
76 1.3 jkunz unsigned int dma_channel;
77 1.3 jkunz uint32_t sc_dma_error;
78 1.3 jkunz uint32_t sc_irq_error;
79 1.3 jkunz uint8_t sc_state;
80 1.3 jkunz uint8_t sc_bus_width;
81 1.3 jkunz } *issp_softc_t;
82 1.1 jkunz
83 1.1 jkunz static int issp_match(device_t, cfdata_t, void *);
84 1.1 jkunz static void issp_attach(device_t, device_t, void *);
85 1.1 jkunz static int issp_activate(device_t, enum devact);
86 1.1 jkunz
87 1.2 jkunz static void issp_reset(struct issp_softc *);
88 1.2 jkunz static void issp_init(struct issp_softc *);
89 1.3 jkunz static uint32_t issp_set_sck(struct issp_softc *, uint32_t);
90 1.3 jkunz static int issp_dma_intr(void *);
91 1.3 jkunz static int issp_error_intr(void *);
92 1.3 jkunz static void issp_ack_intr(struct issp_softc *);
93 1.3 jkunz static void issp_create_dma_cmd_list_multi(issp_softc_t, void *,
94 1.3 jkunz struct sdmmc_command *);
95 1.3 jkunz static void issp_create_dma_cmd_list_single(issp_softc_t, void *,
96 1.3 jkunz struct sdmmc_command *);
97 1.3 jkunz static void issp_create_dma_cmd_list(issp_softc_t, void *,
98 1.3 jkunz struct sdmmc_command *);
99 1.2 jkunz
100 1.2 jkunz /* sdmmc(4) driver chip function prototypes. */
101 1.1 jkunz static int issp_host_reset(sdmmc_chipset_handle_t);
102 1.1 jkunz static uint32_t issp_host_ocr(sdmmc_chipset_handle_t);
103 1.1 jkunz static int issp_host_maxblklen(sdmmc_chipset_handle_t);
104 1.1 jkunz static int issp_card_detect(sdmmc_chipset_handle_t);
105 1.1 jkunz static int issp_write_protect(sdmmc_chipset_handle_t);
106 1.1 jkunz static int issp_bus_power(sdmmc_chipset_handle_t, uint32_t);
107 1.1 jkunz static int issp_bus_clock(sdmmc_chipset_handle_t, int);
108 1.1 jkunz static int issp_bus_width(sdmmc_chipset_handle_t, int);
109 1.1 jkunz static int issp_bus_rod(sdmmc_chipset_handle_t, int);
110 1.1 jkunz static void issp_exec_command(sdmmc_chipset_handle_t,
111 1.3 jkunz struct sdmmc_command *);
112 1.1 jkunz static void issp_card_enable_intr(sdmmc_chipset_handle_t, int);
113 1.1 jkunz static void issp_card_intr_ack(sdmmc_chipset_handle_t);
114 1.1 jkunz
115 1.1 jkunz static struct sdmmc_chip_functions issp_functions = {
116 1.1 jkunz .host_reset = issp_host_reset,
117 1.1 jkunz .host_ocr = issp_host_ocr,
118 1.1 jkunz .host_maxblklen = issp_host_maxblklen,
119 1.1 jkunz .card_detect = issp_card_detect,
120 1.1 jkunz .write_protect = issp_write_protect,
121 1.1 jkunz .bus_power = issp_bus_power,
122 1.1 jkunz .bus_clock = issp_bus_clock,
123 1.1 jkunz .bus_width = issp_bus_width,
124 1.1 jkunz .bus_rod = issp_bus_rod,
125 1.1 jkunz .exec_command = issp_exec_command,
126 1.1 jkunz .card_enable_intr = issp_card_enable_intr,
127 1.1 jkunz .card_intr_ack = issp_card_intr_ack
128 1.1 jkunz };
129 1.1 jkunz
130 1.2 jkunz CFATTACH_DECL3_NEW(ssp,
131 1.2 jkunz sizeof(struct issp_softc),
132 1.2 jkunz issp_match,
133 1.2 jkunz issp_attach,
134 1.2 jkunz NULL,
135 1.2 jkunz issp_activate,
136 1.2 jkunz NULL,
137 1.2 jkunz NULL,
138 1.3 jkunz 0
139 1.3 jkunz );
140 1.2 jkunz
141 1.2 jkunz #define SSP_SOFT_RST_LOOP 455 /* At least 1 us ... */
142 1.2 jkunz
143 1.2 jkunz #define SSP_RD(sc, reg) \
144 1.1 jkunz bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
145 1.2 jkunz #define SSP_WR(sc, reg, val) \
146 1.1 jkunz bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
147 1.1 jkunz
148 1.2 jkunz #define SSP_CLK 96000000 /* CLK_SSP from PLL is 96 MHz */
149 1.2 jkunz #define SSP_CLK_MIN 400 /* 400 kHz */
150 1.2 jkunz #define SSP_CLK_MAX 48000 /* 48 MHz */
151 1.2 jkunz
152 1.3 jkunz /* DATA_TIMEOUT is calculated as: * (1 / SSP_CLK) * (DATA_TIMEOUT * 4096) */
153 1.3 jkunz #define DATA_TIMEOUT 0x4240 /* 723ms */
154 1.2 jkunz
155 1.2 jkunz #define BUS_WIDTH_1_BIT 0x0
156 1.2 jkunz #define BUS_WIDTH_4_BIT 0x1
157 1.2 jkunz #define BUS_WIDTH_8_BIT 0x2
158 1.2 jkunz
159 1.3 jkunz #define SSP1_ATTACHED 1
160 1.3 jkunz #define SSP2_ATTACHED 2
161 1.3 jkunz
162 1.3 jkunz /* Flags for sc_state. */
163 1.3 jkunz #define SSP_STATE_IDLE 0
164 1.3 jkunz #define SSP_STATE_DMA 1
165 1.3 jkunz
166 1.3 jkunz #define PIO_WORD_CTRL0 0
167 1.3 jkunz #define PIO_WORD_CMD0 1
168 1.3 jkunz #define PIO_WORD_CMD1 2
169 1.3 jkunz
170 1.3 jkunz #define HW_SSP_CTRL1_IRQ_MASK ( \
171 1.3 jkunz HW_SSP_CTRL1_SDIO_IRQ | \
172 1.3 jkunz HW_SSP_CTRL1_RESP_ERR_IRQ | \
173 1.3 jkunz HW_SSP_CTRL1_RESP_TIMEOUT_IRQ | \
174 1.3 jkunz HW_SSP_CTRL1_DATA_TIMEOUT_IRQ | \
175 1.3 jkunz HW_SSP_CTRL1_DATA_CRC_IRQ | \
176 1.3 jkunz HW_SSP_CTRL1_FIFO_UNDERRUN_IRQ | \
177 1.3 jkunz HW_SSP_CTRL1_RECV_TIMEOUT_IRQ | \
178 1.3 jkunz HW_SSP_CTRL1_FIFO_OVERRUN_IRQ)
179 1.3 jkunz
180 1.3 jkunz /* SSP does not support over 64k transfer size. */
181 1.3 jkunz #define MAX_TRANSFER_SIZE 65536
182 1.3 jkunz
183 1.1 jkunz static int
184 1.1 jkunz issp_match(device_t parent, cfdata_t match, void *aux)
185 1.1 jkunz {
186 1.1 jkunz struct apb_attach_args *aa = aux;
187 1.1 jkunz
188 1.1 jkunz if ((aa->aa_addr == HW_SSP1_BASE) && (aa->aa_size == HW_SSP1_SIZE))
189 1.1 jkunz return 1;
190 1.1 jkunz
191 1.1 jkunz if ((aa->aa_addr == HW_SSP2_BASE) && (aa->aa_size == HW_SSP2_SIZE))
192 1.1 jkunz return 1;
193 1.1 jkunz
194 1.1 jkunz return 0;
195 1.1 jkunz }
196 1.1 jkunz
197 1.1 jkunz static void
198 1.1 jkunz issp_attach(device_t parent, device_t self, void *aux)
199 1.1 jkunz {
200 1.1 jkunz struct issp_softc *sc = device_private(self);
201 1.2 jkunz struct apb_softc *sc_parent = device_private(parent);
202 1.1 jkunz struct apb_attach_args *aa = aux;
203 1.1 jkunz struct sdmmcbus_attach_args saa;
204 1.3 jkunz static int ssp_attached = 0;
205 1.3 jkunz int error;
206 1.3 jkunz void *intr;
207 1.3 jkunz
208 1.3 jkunz sc->sc_dev = self;
209 1.3 jkunz sc->sc_iot = aa->aa_iot;
210 1.3 jkunz sc->sc_dmat = aa->aa_dmat;
211 1.3 jkunz
212 1.3 jkunz /* Test if device instance is already attached. */
213 1.3 jkunz if (aa->aa_addr == HW_SSP1_BASE && ISSET(ssp_attached, SSP1_ATTACHED)) {
214 1.3 jkunz aprint_error_dev(sc->sc_dev, "SSP1 already attached\n");
215 1.3 jkunz return;
216 1.3 jkunz }
217 1.3 jkunz if (aa->aa_addr == HW_SSP2_BASE && ISSET(ssp_attached, SSP2_ATTACHED)) {
218 1.3 jkunz aprint_error_dev(sc->sc_dev, "SSP2 already attached\n");
219 1.3 jkunz return;
220 1.3 jkunz }
221 1.3 jkunz
222 1.3 jkunz if (aa->aa_addr == HW_SSP1_BASE) {
223 1.3 jkunz sc->dma_channel = APBH_DMA_CHANNEL_SSP1;
224 1.3 jkunz }
225 1.3 jkunz if (aa->aa_addr == HW_SSP2_BASE) {
226 1.3 jkunz sc->dma_channel = APBH_DMA_CHANNEL_SSP2;
227 1.3 jkunz }
228 1.3 jkunz
229 1.3 jkunz /* This driver requires DMA functionality from the bus.
230 1.3 jkunz * Parent bus passes handle to the DMA controller instance. */
231 1.3 jkunz if (sc_parent->dmac == NULL) {
232 1.3 jkunz aprint_error_dev(sc->sc_dev, "DMA functionality missing\n");
233 1.3 jkunz return;
234 1.3 jkunz }
235 1.3 jkunz sc->sc_dmac = device_private(sc_parent->dmac);
236 1.3 jkunz
237 1.3 jkunz /* Initialize lock. */
238 1.3 jkunz mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SDMMC);
239 1.2 jkunz
240 1.3 jkunz /* Condvar to wait interrupt complete. */
241 1.3 jkunz cv_init(&sc->sc_intr_cv, "ssp_intr");
242 1.3 jkunz
243 1.3 jkunz /* Establish interrupt handlers for SSP errors and SSP DMA. */
244 1.3 jkunz if (aa->aa_addr == HW_SSP1_BASE) {
245 1.3 jkunz intr = intr_establish(IRQ_SSP1_DMA, IPL_SDMMC, IST_LEVEL,
246 1.3 jkunz issp_dma_intr, sc);
247 1.3 jkunz if (intr == NULL) {
248 1.3 jkunz aprint_error_dev(sc->sc_dev, "Unable to establish "
249 1.3 jkunz "interrupt for SSP1 DMA\n");
250 1.3 jkunz return;
251 1.3 jkunz }
252 1.3 jkunz intr = intr_establish(IRQ_SSP1_ERROR, IPL_SDMMC, IST_LEVEL,
253 1.3 jkunz issp_error_intr, sc);
254 1.3 jkunz if (intr == NULL) {
255 1.3 jkunz aprint_error_dev(sc->sc_dev, "Unable to establish "
256 1.3 jkunz "interrupt for SSP1 ERROR\n");
257 1.3 jkunz return;
258 1.3 jkunz }
259 1.3 jkunz }
260 1.3 jkunz
261 1.3 jkunz if (aa->aa_addr == HW_SSP2_BASE) {
262 1.3 jkunz intr = intr_establish(IRQ_SSP2_DMA, IPL_SDMMC, IST_LEVEL,
263 1.3 jkunz issp_dma_intr, sc);
264 1.3 jkunz if (intr == NULL) {
265 1.3 jkunz aprint_error_dev(sc->sc_dev, "Unable to establish "
266 1.3 jkunz "interrupt for SSP2 DMA\n");
267 1.3 jkunz return;
268 1.3 jkunz }
269 1.3 jkunz intr = intr_establish(IRQ_SSP2_ERROR, IPL_SDMMC, IST_LEVEL,
270 1.3 jkunz issp_error_intr, sc);
271 1.3 jkunz if (intr == NULL) {
272 1.3 jkunz aprint_error_dev(sc->sc_dev, "Unable to establish "
273 1.3 jkunz "interrupt for SSP2 ERROR\n");
274 1.3 jkunz return;
275 1.3 jkunz }
276 1.3 jkunz }
277 1.3 jkunz
278 1.3 jkunz /* Allocate DMA handle. */
279 1.3 jkunz error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, 1, MAXPHYS,
280 1.3 jkunz 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &sc->sc_dmamp);
281 1.3 jkunz if (error) {
282 1.3 jkunz aprint_error_dev(sc->sc_dev,
283 1.3 jkunz "Unable to allocate DMA handle\n");
284 1.3 jkunz return;
285 1.3 jkunz }
286 1.3 jkunz
287 1.3 jkunz /* Allocate memory for DMA command chain. */
288 1.3 jkunz sc->sc_chnsiz = sizeof(struct apbdma_command) *
289 1.3 jkunz (MAX_TRANSFER_SIZE / SDMMC_SECTOR_SIZE);
290 1.3 jkunz
291 1.3 jkunz error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_chnsiz, PAGE_SIZE, 0,
292 1.3 jkunz sc->sc_ds, 1, &sc->sc_rseg, BUS_DMA_NOWAIT);
293 1.3 jkunz if (error) {
294 1.3 jkunz aprint_error_dev(sc->sc_dev,
295 1.3 jkunz "Unable to allocate DMA memory\n");
296 1.1 jkunz return;
297 1.3 jkunz }
298 1.1 jkunz
299 1.3 jkunz /* Initialize DMA channel. */
300 1.3 jkunz apbdma_chan_init(sc->sc_dmac, sc->dma_channel);
301 1.1 jkunz
302 1.3 jkunz /* Map SSP bus space. */
303 1.3 jkunz if (bus_space_map(sc->sc_iot, aa->aa_addr, aa->aa_size, 0,
304 1.3 jkunz &sc->sc_hdl)) {
305 1.3 jkunz aprint_error_dev(sc->sc_dev, "Unable to map SSP bus space\n");
306 1.1 jkunz return;
307 1.1 jkunz }
308 1.1 jkunz
309 1.1 jkunz issp_reset(sc);
310 1.2 jkunz issp_init(sc);
311 1.1 jkunz
312 1.2 jkunz uint32_t issp_vers = SSP_RD(sc, HW_SSP_VERSION);
313 1.1 jkunz aprint_normal(": SSP Block v%" __PRIuBIT ".%" __PRIuBIT "\n",
314 1.1 jkunz __SHIFTOUT(issp_vers, HW_SSP_VERSION_MAJOR),
315 1.1 jkunz __SHIFTOUT(issp_vers, HW_SSP_VERSION_MINOR));
316 1.1 jkunz
317 1.3 jkunz /* Attach sdmmc to ssp bus. */
318 1.1 jkunz saa.saa_busname = "sdmmc";
319 1.1 jkunz saa.saa_sct = &issp_functions;
320 1.1 jkunz saa.saa_spi_sct = NULL;
321 1.1 jkunz saa.saa_sch = sc;
322 1.1 jkunz saa.saa_dmat = aa->aa_dmat;
323 1.1 jkunz saa.saa_clkmin = SSP_CLK_MIN;
324 1.1 jkunz saa.saa_clkmax = SSP_CLK_MAX;
325 1.3 jkunz saa.saa_caps = SMC_CAPS_DMA | SMC_CAPS_4BIT_MODE |
326 1.3 jkunz SMC_CAPS_MULTI_SEG_DMA;
327 1.1 jkunz
328 1.1 jkunz sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL);
329 1.1 jkunz if (sc->sc_sdmmc == NULL) {
330 1.1 jkunz aprint_error_dev(sc->sc_dev, "unable to attach sdmmc\n");
331 1.1 jkunz return;
332 1.1 jkunz }
333 1.1 jkunz
334 1.3 jkunz /* Device instance was succesfully attached. */
335 1.3 jkunz if (aa->aa_addr == HW_SSP1_BASE)
336 1.3 jkunz ssp_attached |= SSP1_ATTACHED;
337 1.3 jkunz if (aa->aa_addr == HW_SSP2_BASE)
338 1.3 jkunz ssp_attached |= SSP2_ATTACHED;
339 1.1 jkunz
340 1.1 jkunz return;
341 1.1 jkunz }
342 1.1 jkunz
343 1.1 jkunz static int
344 1.1 jkunz issp_activate(device_t self, enum devact act)
345 1.1 jkunz {
346 1.1 jkunz return EOPNOTSUPP;
347 1.1 jkunz }
348 1.1 jkunz
349 1.1 jkunz /*
350 1.1 jkunz * sdmmc chip functions.
351 1.1 jkunz */
352 1.1 jkunz static int
353 1.1 jkunz issp_host_reset(sdmmc_chipset_handle_t sch)
354 1.1 jkunz {
355 1.1 jkunz struct issp_softc *sc = sch;
356 1.1 jkunz issp_reset(sc);
357 1.1 jkunz return 0;
358 1.1 jkunz }
359 1.1 jkunz
360 1.1 jkunz static uint32_t
361 1.1 jkunz issp_host_ocr(sdmmc_chipset_handle_t sch)
362 1.1 jkunz {
363 1.3 jkunz /* SSP supports at least 3.2 - 3.3v */
364 1.1 jkunz return MMC_OCR_3_2V_3_3V;
365 1.1 jkunz }
366 1.1 jkunz
367 1.1 jkunz static int
368 1.1 jkunz issp_host_maxblklen(sdmmc_chipset_handle_t sch)
369 1.1 jkunz {
370 1.1 jkunz return 512;
371 1.1 jkunz }
372 1.1 jkunz
373 1.1 jkunz /*
374 1.1 jkunz * Called at the beginning of sdmmc_task_thread to detect the presence
375 1.1 jkunz * of the SD card.
376 1.1 jkunz */
377 1.1 jkunz static int
378 1.1 jkunz issp_card_detect(sdmmc_chipset_handle_t sch)
379 1.1 jkunz {
380 1.1 jkunz return 1;
381 1.1 jkunz }
382 1.1 jkunz
383 1.1 jkunz static int
384 1.1 jkunz issp_write_protect(sdmmc_chipset_handle_t sch)
385 1.1 jkunz {
386 1.1 jkunz /* The device is not write protected. */
387 1.1 jkunz return 0;
388 1.1 jkunz }
389 1.1 jkunz
390 1.1 jkunz static int
391 1.2 jkunz issp_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
392 1.1 jkunz {
393 1.2 jkunz /* i.MX23 SSP does not support setting bus power. */
394 1.1 jkunz return 0;
395 1.1 jkunz }
396 1.1 jkunz
397 1.1 jkunz static int
398 1.1 jkunz issp_bus_clock(sdmmc_chipset_handle_t sch, int clock)
399 1.1 jkunz {
400 1.1 jkunz struct issp_softc *sc = sch;
401 1.1 jkunz uint32_t sck;
402 1.1 jkunz
403 1.3 jkunz if (clock < SSP_CLK_MIN)
404 1.3 jkunz sck = issp_set_sck(sc, SSP_CLK_MIN * 1000);
405 1.3 jkunz else
406 1.3 jkunz sck = issp_set_sck(sc, clock * 1000);
407 1.2 jkunz
408 1.3 jkunz /* Notify user if we didn't get the exact clock rate from SSP that was
409 1.3 jkunz * requested from the SDMMC subsystem. */
410 1.3 jkunz if (sck != clock * 1000) {
411 1.3 jkunz sck = sck / 1000;
412 1.3 jkunz if (((sck) / 1000) != 0)
413 1.3 jkunz aprint_normal_dev(sc->sc_dev, "bus clock @ %u.%03u "
414 1.3 jkunz "MHz\n", sck / 1000, sck % 1000);
415 1.3 jkunz else
416 1.3 jkunz aprint_normal_dev(sc->sc_dev, "bus clock @ %u KHz\n",
417 1.3 jkunz sck % 1000);
418 1.3 jkunz }
419 1.1 jkunz
420 1.1 jkunz return 0;
421 1.1 jkunz }
422 1.1 jkunz
423 1.1 jkunz static int
424 1.1 jkunz issp_bus_width(sdmmc_chipset_handle_t sch, int width)
425 1.1 jkunz {
426 1.2 jkunz struct issp_softc *sc = sch;
427 1.2 jkunz
428 1.2 jkunz switch(width) {
429 1.2 jkunz case(1):
430 1.3 jkunz sc->sc_bus_width = BUS_WIDTH_1_BIT;
431 1.2 jkunz break;
432 1.2 jkunz case(4):
433 1.3 jkunz sc->sc_bus_width = BUS_WIDTH_4_BIT;
434 1.2 jkunz break;
435 1.2 jkunz case(8):
436 1.3 jkunz sc->sc_bus_width = BUS_WIDTH_8_BIT;
437 1.2 jkunz break;
438 1.2 jkunz default:
439 1.2 jkunz return 1;
440 1.2 jkunz }
441 1.2 jkunz
442 1.2 jkunz return 0;
443 1.1 jkunz }
444 1.1 jkunz
445 1.1 jkunz static int
446 1.1 jkunz issp_bus_rod(sdmmc_chipset_handle_t sch, int rod)
447 1.1 jkunz {
448 1.1 jkunz /* Go to data transfer mode. */
449 1.1 jkunz return 0;
450 1.1 jkunz }
451 1.1 jkunz
452 1.1 jkunz static void
453 1.1 jkunz issp_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
454 1.1 jkunz {
455 1.3 jkunz issp_softc_t sc = sch;
456 1.3 jkunz void *dma_chain;
457 1.3 jkunz int error;
458 1.3 jkunz
459 1.3 jkunz /* SSP does not support over 64k transfer size. */
460 1.3 jkunz if (cmd->c_data != NULL && cmd->c_datalen > MAX_TRANSFER_SIZE) {
461 1.3 jkunz aprint_error_dev(sc->sc_dev, "transfer size over %d: %d\n",
462 1.3 jkunz MAX_TRANSFER_SIZE, cmd->c_datalen);
463 1.3 jkunz cmd->c_error = ENODEV;
464 1.3 jkunz return;
465 1.3 jkunz }
466 1.3 jkunz
467 1.3 jkunz /* Map dma_chain to point allocated previously allocated DMA chain. */
468 1.3 jkunz error = bus_dmamem_map(sc->sc_dmat, sc->sc_ds, 1, sc->sc_chnsiz,
469 1.3 jkunz &dma_chain, BUS_DMA_NOWAIT);
470 1.3 jkunz if (error) {
471 1.3 jkunz aprint_error_dev(sc->sc_dev, "bus_dmamem_map: %d\n", error);
472 1.3 jkunz cmd->c_error = error;
473 1.3 jkunz goto out;
474 1.3 jkunz }
475 1.2 jkunz
476 1.3 jkunz error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamp, dma_chain,
477 1.3 jkunz sc->sc_chnsiz, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
478 1.3 jkunz if (error) {
479 1.3 jkunz aprint_error_dev(sc->sc_dev, "bus_dmamap_load: %d\n", error);
480 1.3 jkunz cmd->c_error = error;
481 1.3 jkunz goto dmamem_unmap;
482 1.3 jkunz }
483 1.1 jkunz
484 1.3 jkunz memset(dma_chain, 0, sc->sc_chnsiz);
485 1.1 jkunz
486 1.3 jkunz /* Setup DMA command chain.*/
487 1.3 jkunz if (cmd->c_data != NULL && (cmd->c_datalen / cmd->c_blklen) > 1) {
488 1.3 jkunz /* Multi block transfer. */
489 1.3 jkunz issp_create_dma_cmd_list_multi(sc, dma_chain, cmd);
490 1.3 jkunz } else if (cmd->c_data != NULL && cmd->c_datalen) {
491 1.3 jkunz /* Single block transfer. */
492 1.3 jkunz issp_create_dma_cmd_list_single(sc, dma_chain, cmd);
493 1.3 jkunz } else {
494 1.3 jkunz /* Only command, no data. */
495 1.3 jkunz issp_create_dma_cmd_list(sc, dma_chain, cmd);
496 1.1 jkunz }
497 1.1 jkunz
498 1.3 jkunz /* Tell DMA controller where it can find just initialized DMA chain. */
499 1.3 jkunz apbdma_chan_set_chain(sc->sc_dmac, sc->dma_channel, sc->sc_dmamp);
500 1.3 jkunz
501 1.3 jkunz /* Synchronize command chain before DMA controller accesses it. */
502 1.3 jkunz bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamp, 0, sc->sc_chnsiz,
503 1.3 jkunz BUS_DMASYNC_PREWRITE);
504 1.3 jkunz
505 1.3 jkunz sc->sc_state = SSP_STATE_DMA;
506 1.3 jkunz sc->sc_irq_error = 0;
507 1.3 jkunz sc->sc_dma_error = 0;
508 1.3 jkunz cmd->c_error = 0;
509 1.3 jkunz
510 1.3 jkunz mutex_enter(&sc->sc_lock);
511 1.1 jkunz
512 1.3 jkunz /* Run DMA command chain. */
513 1.3 jkunz apbdma_run(sc->sc_dmac, sc->dma_channel);
514 1.2 jkunz
515 1.3 jkunz /* Wait DMA to complete. */
516 1.3 jkunz while (sc->sc_state == SSP_STATE_DMA)
517 1.3 jkunz cv_wait(&sc->sc_intr_cv, &sc->sc_lock);
518 1.2 jkunz
519 1.3 jkunz mutex_exit(&sc->sc_lock);
520 1.1 jkunz
521 1.3 jkunz bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamp, 0, sc->sc_chnsiz,
522 1.3 jkunz BUS_DMASYNC_POSTWRITE);
523 1.1 jkunz
524 1.3 jkunz if (sc->sc_dma_error) {
525 1.3 jkunz if (sc->sc_dma_error == DMA_IRQ_TERM) {
526 1.3 jkunz apbdma_chan_reset(sc->sc_dmac, sc->dma_channel);
527 1.3 jkunz cmd->c_error = sc->sc_dma_error;
528 1.2 jkunz }
529 1.3 jkunz else if (sc->sc_dma_error == DMA_IRQ_BUS_ERROR) {
530 1.3 jkunz aprint_error_dev(sc->sc_dev, "DMA_IRQ_BUS_ERROR: %d\n",
531 1.3 jkunz sc->sc_irq_error);
532 1.3 jkunz cmd->c_error = sc->sc_dma_error;
533 1.2 jkunz }
534 1.2 jkunz }
535 1.2 jkunz
536 1.3 jkunz if (sc->sc_irq_error) {
537 1.3 jkunz /* Do not log RESP_TIMEOUT_IRQ error if bus width is 0 as it is
538 1.3 jkunz * expected during SD card initialization phase. */
539 1.3 jkunz if (sc->sc_bus_width) {
540 1.3 jkunz aprint_error_dev(sc->sc_dev, "SSP_ERROR_IRQ: %d\n",
541 1.3 jkunz sc->sc_irq_error);
542 1.3 jkunz }
543 1.3 jkunz else if(!(sc->sc_irq_error & HW_SSP_CTRL1_RESP_TIMEOUT_IRQ)) {
544 1.3 jkunz aprint_error_dev(sc->sc_dev, "SSP_ERROR_IRQ: %d\n",
545 1.3 jkunz sc->sc_irq_error);
546 1.3 jkunz }
547 1.2 jkunz
548 1.3 jkunz /* Shift unsigned error code so it fits nicely to signed int. */
549 1.3 jkunz cmd->c_error = sc->sc_irq_error >> 8;
550 1.3 jkunz }
551 1.1 jkunz
552 1.3 jkunz /* Check reponse from the card if such was requested. */
553 1.1 jkunz if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
554 1.2 jkunz cmd->c_resp[0] = SSP_RD(sc, HW_SSP_SDRESP0);
555 1.1 jkunz if (ISSET(cmd->c_flags, SCF_RSP_136)) {
556 1.2 jkunz cmd->c_resp[1] = SSP_RD(sc, HW_SSP_SDRESP1);
557 1.2 jkunz cmd->c_resp[2] = SSP_RD(sc, HW_SSP_SDRESP2);
558 1.2 jkunz cmd->c_resp[3] = SSP_RD(sc, HW_SSP_SDRESP3);
559 1.2 jkunz /*
560 1.2 jkunz * Remove CRC7 + LSB by rotating all bits right by 8 to
561 1.2 jkunz * make sdmmc __bitfield() happy.
562 1.2 jkunz */
563 1.2 jkunz cmd->c_resp[0] >>= 8; /* Remove CRC7 + LSB. */
564 1.2 jkunz cmd->c_resp[0] |= (0x000000FF & cmd->c_resp[1]) << 24;
565 1.2 jkunz cmd->c_resp[1] >>= 8;
566 1.2 jkunz cmd->c_resp[1] |= (0x000000FF & cmd->c_resp[2]) << 24;
567 1.2 jkunz cmd->c_resp[2] >>= 8;
568 1.2 jkunz cmd->c_resp[2] |= (0x000000FF & cmd->c_resp[3]) << 24;
569 1.2 jkunz cmd->c_resp[3] >>= 8;
570 1.1 jkunz }
571 1.1 jkunz }
572 1.3 jkunz
573 1.3 jkunz bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamp);
574 1.3 jkunz dmamem_unmap:
575 1.3 jkunz bus_dmamem_unmap(sc->sc_dmat, dma_chain, sc->sc_chnsiz);
576 1.3 jkunz out:
577 1.3 jkunz
578 1.1 jkunz return;
579 1.1 jkunz }
580 1.1 jkunz
581 1.1 jkunz static void
582 1.1 jkunz issp_card_enable_intr(sdmmc_chipset_handle_t sch, int irq)
583 1.1 jkunz {
584 1.1 jkunz struct issp_softc *sc = sch;
585 1.3 jkunz aprint_error_dev(sc->sc_dev, "issp_card_enable_intr not implemented\n");
586 1.1 jkunz return;
587 1.1 jkunz }
588 1.1 jkunz
589 1.1 jkunz static void
590 1.1 jkunz issp_card_intr_ack(sdmmc_chipset_handle_t sch)
591 1.1 jkunz {
592 1.1 jkunz struct issp_softc *sc = sch;
593 1.3 jkunz aprint_error_dev(sc->sc_dev, "issp_card_intr_ack not implemented\n");
594 1.1 jkunz return;
595 1.1 jkunz }
596 1.1 jkunz
597 1.1 jkunz /*
598 1.1 jkunz * Reset the SSP block.
599 1.1 jkunz *
600 1.2 jkunz * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
601 1.1 jkunz */
602 1.1 jkunz static void
603 1.1 jkunz issp_reset(struct issp_softc *sc)
604 1.1 jkunz {
605 1.1 jkunz unsigned int loop;
606 1.1 jkunz
607 1.1 jkunz /* Prepare for soft-reset by making sure that SFTRST is not currently
608 1.1 jkunz * asserted. Also clear CLKGATE so we can wait for its assertion below.
609 1.1 jkunz */
610 1.2 jkunz SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
611 1.1 jkunz
612 1.1 jkunz /* Wait at least a microsecond for SFTRST to deassert. */
613 1.1 jkunz loop = 0;
614 1.2 jkunz while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
615 1.1 jkunz (loop < SSP_SOFT_RST_LOOP))
616 1.1 jkunz loop++;
617 1.1 jkunz
618 1.1 jkunz /* Clear CLKGATE so we can wait for its assertion below. */
619 1.2 jkunz SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
620 1.1 jkunz
621 1.1 jkunz /* Soft-reset the block. */
622 1.2 jkunz SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_SFTRST);
623 1.1 jkunz
624 1.1 jkunz /* Wait until clock is in the gated state. */
625 1.2 jkunz while (!(SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE));
626 1.1 jkunz
627 1.1 jkunz /* Bring block out of reset. */
628 1.2 jkunz SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
629 1.1 jkunz
630 1.1 jkunz loop = 0;
631 1.2 jkunz while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
632 1.1 jkunz (loop < SSP_SOFT_RST_LOOP))
633 1.1 jkunz loop++;
634 1.1 jkunz
635 1.2 jkunz SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
636 1.2 jkunz
637 1.1 jkunz /* Wait until clock is in the NON-gated state. */
638 1.2 jkunz while (SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE);
639 1.1 jkunz
640 1.1 jkunz return;
641 1.1 jkunz }
642 1.1 jkunz
643 1.2 jkunz /*
644 1.2 jkunz * Initialize SSP controller to SD/MMC mode.
645 1.1 jkunz */
646 1.1 jkunz static void
647 1.1 jkunz issp_init(struct issp_softc *sc)
648 1.1 jkunz {
649 1.1 jkunz uint32_t reg;
650 1.1 jkunz
651 1.3 jkunz reg = SSP_RD(sc, HW_SSP_CTRL0);
652 1.3 jkunz reg |= HW_SSP_CTRL0_ENABLE;
653 1.3 jkunz
654 1.2 jkunz /* Initial data bus width is 1-bit. */
655 1.1 jkunz reg &= ~(HW_SSP_CTRL0_BUS_WIDTH);
656 1.2 jkunz reg |= __SHIFTIN(BUS_WIDTH_1_BIT, HW_SSP_CTRL0_BUS_WIDTH) |
657 1.2 jkunz HW_SSP_CTRL0_WAIT_FOR_IRQ | HW_SSP_CTRL0_ENABLE;
658 1.2 jkunz SSP_WR(sc, HW_SSP_CTRL0, reg);
659 1.3 jkunz sc->sc_bus_width = BUS_WIDTH_1_BIT;
660 1.1 jkunz
661 1.2 jkunz /* Set data timeout. */
662 1.2 jkunz reg = SSP_RD(sc, HW_SSP_TIMING);
663 1.2 jkunz reg &= ~(HW_SSP_TIMING_TIMEOUT);
664 1.2 jkunz reg |= __SHIFTIN(DATA_TIMEOUT, HW_SSP_TIMING_TIMEOUT);
665 1.3 jkunz SSP_WR(sc, HW_SSP_TIMING, reg);
666 1.2 jkunz
667 1.2 jkunz /* Set initial clock rate to minimum. */
668 1.2 jkunz issp_set_sck(sc, SSP_CLK_MIN * 1000);
669 1.2 jkunz
670 1.2 jkunz reg = SSP_RD(sc, HW_SSP_CTRL1);
671 1.3 jkunz /* Enable all but SDIO IRQ's. */
672 1.3 jkunz reg |= HW_SSP_CTRL1_RESP_ERR_IRQ_EN |
673 1.3 jkunz HW_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN |
674 1.3 jkunz HW_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN |
675 1.3 jkunz HW_SSP_CTRL1_DATA_CRC_IRQ_EN |
676 1.3 jkunz HW_SSP_CTRL1_FIFO_UNDERRUN_EN |
677 1.3 jkunz HW_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN |
678 1.3 jkunz HW_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN;
679 1.3 jkunz reg |= HW_SSP_CTRL1_DMA_ENABLE;
680 1.3 jkunz reg |= HW_SSP_CTRL1_POLARITY;
681 1.3 jkunz /* Set SD/MMC mode and use use 8-bits per word. */
682 1.1 jkunz reg &= ~(HW_SSP_CTRL1_WORD_LENGTH | HW_SSP_CTRL1_SSP_MODE);
683 1.3 jkunz reg |= __SHIFTIN(0x7, HW_SSP_CTRL1_WORD_LENGTH) |
684 1.1 jkunz __SHIFTIN(0x3, HW_SSP_CTRL1_SSP_MODE);
685 1.2 jkunz SSP_WR(sc, HW_SSP_CTRL1, reg);
686 1.1 jkunz
687 1.1 jkunz return;
688 1.1 jkunz }
689 1.1 jkunz
690 1.1 jkunz /*
691 1.1 jkunz * Set SSP_SCK clock rate to the value specified in target.
692 1.1 jkunz *
693 1.1 jkunz * SSP_SCK is calculated as: SSP_CLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE))
694 1.1 jkunz *
695 1.3 jkunz * issp_set_sck finds the most suitable CLOCK_DIVIDE and CLOCK_RATE register
696 1.1 jkunz * values for the target clock rate by iterating through all possible register
697 1.1 jkunz * values.
698 1.1 jkunz */
699 1.1 jkunz static uint32_t
700 1.1 jkunz issp_set_sck(struct issp_softc *sc, uint32_t target)
701 1.1 jkunz {
702 1.1 jkunz uint32_t newclk, found, reg;
703 1.1 jkunz uint8_t div, rate, d, r;
704 1.1 jkunz
705 1.1 jkunz found = div = rate = 0;
706 1.1 jkunz
707 1.1 jkunz for (d = 2; d < 254; d++) {
708 1.1 jkunz for (r = 0; r < 255; r++) {
709 1.1 jkunz newclk = SSP_CLK / (d * (1 + r));
710 1.1 jkunz if (newclk == target) {
711 1.1 jkunz found = newclk;
712 1.1 jkunz div = d;
713 1.1 jkunz rate = r;
714 1.1 jkunz goto out;
715 1.1 jkunz }
716 1.1 jkunz if (newclk < target && newclk > found) {
717 1.1 jkunz found = newclk;
718 1.1 jkunz div = d;
719 1.1 jkunz rate = r;
720 1.1 jkunz }
721 1.1 jkunz }
722 1.1 jkunz }
723 1.1 jkunz out:
724 1.2 jkunz reg = SSP_RD(sc, HW_SSP_TIMING);
725 1.1 jkunz reg &= ~(HW_SSP_TIMING_CLOCK_DIVIDE | HW_SSP_TIMING_CLOCK_RATE);
726 1.1 jkunz reg |= __SHIFTIN(div, HW_SSP_TIMING_CLOCK_DIVIDE) |
727 1.1 jkunz __SHIFTIN(rate, HW_SSP_TIMING_CLOCK_RATE);
728 1.2 jkunz SSP_WR(sc, HW_SSP_TIMING, reg);
729 1.1 jkunz
730 1.2 jkunz return SSP_CLK / (div * (1 + rate));
731 1.1 jkunz }
732 1.3 jkunz
733 1.3 jkunz /*
734 1.3 jkunz * IRQ from DMA.
735 1.3 jkunz */
736 1.3 jkunz static int
737 1.3 jkunz issp_dma_intr(void *arg)
738 1.3 jkunz {
739 1.3 jkunz issp_softc_t sc = arg;
740 1.3 jkunz unsigned int dma_err;
741 1.3 jkunz
742 1.3 jkunz dma_err = apbdma_intr_status(sc->sc_dmac, sc->dma_channel);
743 1.3 jkunz
744 1.3 jkunz if (dma_err) {
745 1.3 jkunz apbdma_ack_error_intr(sc->sc_dmac, sc->dma_channel);
746 1.3 jkunz } else {
747 1.3 jkunz apbdma_ack_intr(sc->sc_dmac, sc->dma_channel);
748 1.3 jkunz }
749 1.3 jkunz
750 1.3 jkunz mutex_enter(&sc->sc_lock);
751 1.3 jkunz
752 1.3 jkunz sc->sc_dma_error = dma_err;
753 1.3 jkunz sc->sc_state = SSP_STATE_IDLE;
754 1.3 jkunz
755 1.3 jkunz /* Signal thread that interrupt was handled. */
756 1.3 jkunz cv_signal(&sc->sc_intr_cv);
757 1.3 jkunz
758 1.3 jkunz mutex_exit(&sc->sc_lock);
759 1.3 jkunz
760 1.3 jkunz /* Return 1 to acknowledge IRQ. */
761 1.3 jkunz return 1;
762 1.3 jkunz }
763 1.3 jkunz
764 1.3 jkunz /*
765 1.3 jkunz * IRQ from SSP block.
766 1.3 jkunz *
767 1.3 jkunz * When SSP receives IRQ it terminates ongoing DMA transfer by issuing DMATERM
768 1.3 jkunz * signal to DMA block.
769 1.3 jkunz */
770 1.3 jkunz static int
771 1.3 jkunz issp_error_intr(void *arg)
772 1.3 jkunz {
773 1.3 jkunz issp_softc_t sc = arg;
774 1.3 jkunz
775 1.3 jkunz mutex_enter(&sc->sc_lock);
776 1.3 jkunz
777 1.3 jkunz sc->sc_irq_error =
778 1.3 jkunz SSP_RD(sc, HW_SSP_CTRL1) & HW_SSP_CTRL1_IRQ_MASK;
779 1.3 jkunz
780 1.3 jkunz issp_ack_intr(sc);
781 1.3 jkunz
782 1.3 jkunz mutex_exit(&sc->sc_lock);
783 1.3 jkunz
784 1.3 jkunz /* Return 1 to acknowledge IRQ. */
785 1.3 jkunz return 1;
786 1.3 jkunz }
787 1.3 jkunz
788 1.3 jkunz /*
789 1.3 jkunz * Acknowledge SSP error IRQ.
790 1.3 jkunz */
791 1.3 jkunz static void
792 1.3 jkunz issp_ack_intr(struct issp_softc *sc)
793 1.3 jkunz {
794 1.3 jkunz
795 1.3 jkunz /* Acknowledge all IRQ's. */
796 1.3 jkunz SSP_WR(sc, HW_SSP_CTRL1_CLR, HW_SSP_CTRL1_IRQ_MASK);
797 1.3 jkunz
798 1.3 jkunz return;
799 1.3 jkunz }
800 1.3 jkunz
801 1.3 jkunz /*
802 1.3 jkunz * Set up multi block DMA transfer.
803 1.3 jkunz */
804 1.3 jkunz static void
805 1.3 jkunz issp_create_dma_cmd_list_multi(issp_softc_t sc, void *dma_chain,
806 1.3 jkunz struct sdmmc_command *cmd)
807 1.3 jkunz {
808 1.3 jkunz apbdma_command_t dma_cmd;
809 1.3 jkunz int blocks;
810 1.3 jkunz int nblk;
811 1.3 jkunz
812 1.3 jkunz blocks = cmd->c_datalen / cmd->c_blklen;
813 1.3 jkunz nblk = 0;
814 1.3 jkunz dma_cmd = dma_chain;
815 1.3 jkunz
816 1.3 jkunz /* HEAD */
817 1.3 jkunz apbdma_cmd_buf(&dma_cmd[nblk], cmd->c_blklen * nblk, cmd->c_dmamap);
818 1.3 jkunz apbdma_cmd_chain(&dma_cmd[nblk], &dma_cmd[nblk+1], dma_chain,
819 1.3 jkunz sc->sc_dmamp);
820 1.3 jkunz
821 1.3 jkunz dma_cmd[nblk].control =
822 1.3 jkunz __SHIFTIN(cmd->c_blklen, APBDMA_CMD_XFER_COUNT) |
823 1.3 jkunz __SHIFTIN(3, APBDMA_CMD_CMDPIOWORDS) | APBDMA_CMD_HALTONTERMINATE |
824 1.3 jkunz APBDMA_CMD_CHAIN;
825 1.3 jkunz
826 1.3 jkunz if (!ISSET(cmd->c_flags, SCF_RSP_CRC)) {
827 1.3 jkunz dma_cmd[nblk].pio_words[PIO_WORD_CTRL0] |=
828 1.3 jkunz HW_SSP_CTRL0_IGNORE_CRC;
829 1.3 jkunz }
830 1.3 jkunz
831 1.3 jkunz dma_cmd[nblk].pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_DATA_XFER |
832 1.3 jkunz __SHIFTIN(sc->sc_bus_width, HW_SSP_CTRL0_BUS_WIDTH) |
833 1.3 jkunz HW_SSP_CTRL0_WAIT_FOR_IRQ |
834 1.3 jkunz __SHIFTIN(cmd->c_datalen, HW_SSP_CTRL0_XFER_COUNT);
835 1.3 jkunz
836 1.3 jkunz if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
837 1.3 jkunz dma_cmd[nblk].pio_words[PIO_WORD_CTRL0] |=
838 1.3 jkunz HW_SSP_CTRL0_GET_RESP;
839 1.3 jkunz if (ISSET(cmd->c_flags, SCF_RSP_136)) {
840 1.3 jkunz dma_cmd[nblk].pio_words[PIO_WORD_CTRL0] |=
841 1.3 jkunz HW_SSP_CTRL0_LONG_RESP;
842 1.3 jkunz }
843 1.3 jkunz }
844 1.3 jkunz
845 1.3 jkunz dma_cmd[nblk].pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_ENABLE;
846 1.3 jkunz
847 1.3 jkunz dma_cmd[nblk].pio_words[PIO_WORD_CMD0] =
848 1.3 jkunz __SHIFTIN(ffs(cmd->c_blklen) - 1, HW_SSP_CMD0_BLOCK_SIZE) |
849 1.3 jkunz __SHIFTIN(blocks - 1, HW_SSP_CMD0_BLOCK_COUNT) |
850 1.3 jkunz __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD);
851 1.3 jkunz
852 1.3 jkunz dma_cmd[nblk].pio_words[PIO_WORD_CMD1] = cmd->c_arg;
853 1.3 jkunz
854 1.3 jkunz if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
855 1.3 jkunz dma_cmd[nblk].control |=
856 1.3 jkunz __SHIFTIN(APBDMA_CMD_DMA_WRITE, APBDMA_CMD_COMMAND);
857 1.3 jkunz dma_cmd[nblk].pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_READ;
858 1.3 jkunz } else {
859 1.3 jkunz dma_cmd[nblk].control |=
860 1.3 jkunz __SHIFTIN(APBDMA_CMD_DMA_READ, APBDMA_CMD_COMMAND);
861 1.3 jkunz }
862 1.3 jkunz
863 1.3 jkunz nblk++;
864 1.3 jkunz
865 1.3 jkunz /* BODY: Build commands for blocks between head and tail, if any. */
866 1.3 jkunz for (; nblk < blocks - 1; nblk++) {
867 1.3 jkunz
868 1.3 jkunz apbdma_cmd_buf(&dma_cmd[nblk], cmd->c_blklen * nblk,
869 1.3 jkunz cmd->c_dmamap);
870 1.3 jkunz
871 1.3 jkunz apbdma_cmd_chain(&dma_cmd[nblk], &dma_cmd[nblk+1], dma_chain,
872 1.3 jkunz sc->sc_dmamp);
873 1.3 jkunz
874 1.3 jkunz dma_cmd[nblk].control =
875 1.3 jkunz __SHIFTIN(cmd->c_blklen, APBDMA_CMD_XFER_COUNT) |
876 1.3 jkunz APBDMA_CMD_HALTONTERMINATE | APBDMA_CMD_CHAIN;
877 1.3 jkunz
878 1.3 jkunz if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
879 1.3 jkunz dma_cmd[nblk].control |=
880 1.3 jkunz __SHIFTIN(APBDMA_CMD_DMA_WRITE,
881 1.3 jkunz APBDMA_CMD_COMMAND);
882 1.3 jkunz } else {
883 1.3 jkunz dma_cmd[nblk].control |=
884 1.3 jkunz __SHIFTIN(APBDMA_CMD_DMA_READ, APBDMA_CMD_COMMAND);
885 1.3 jkunz }
886 1.3 jkunz }
887 1.3 jkunz
888 1.3 jkunz /* TAIL
889 1.3 jkunz *
890 1.3 jkunz * TODO: Send CMD12/STOP with last DMA command to support
891 1.3 jkunz * SMC_CAPS_AUTO_STOP.
892 1.3 jkunz */
893 1.3 jkunz apbdma_cmd_buf(&dma_cmd[nblk], cmd->c_blklen * nblk, cmd->c_dmamap);
894 1.3 jkunz /* next = NULL */
895 1.3 jkunz dma_cmd[nblk].control =
896 1.3 jkunz __SHIFTIN(cmd->c_blklen, APBDMA_CMD_XFER_COUNT) |
897 1.3 jkunz APBDMA_CMD_HALTONTERMINATE | APBDMA_CMD_WAIT4ENDCMD |
898 1.3 jkunz APBDMA_CMD_SEMAPHORE | APBDMA_CMD_IRQONCMPLT;
899 1.3 jkunz
900 1.3 jkunz if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
901 1.3 jkunz dma_cmd[nblk].control |= __SHIFTIN(APBDMA_CMD_DMA_WRITE,
902 1.3 jkunz APBDMA_CMD_COMMAND);
903 1.3 jkunz } else {
904 1.3 jkunz dma_cmd[nblk].control |= __SHIFTIN(APBDMA_CMD_DMA_READ,
905 1.3 jkunz APBDMA_CMD_COMMAND);
906 1.3 jkunz }
907 1.3 jkunz
908 1.3 jkunz return;
909 1.3 jkunz }
910 1.3 jkunz
911 1.3 jkunz /*
912 1.3 jkunz * Set up single block DMA transfer.
913 1.3 jkunz */
914 1.3 jkunz static void
915 1.3 jkunz issp_create_dma_cmd_list_single(issp_softc_t sc, void *dma_chain,
916 1.3 jkunz struct sdmmc_command *cmd)
917 1.3 jkunz {
918 1.3 jkunz apbdma_command_t dma_cmd;
919 1.3 jkunz
920 1.3 jkunz dma_cmd = dma_chain;
921 1.3 jkunz
922 1.3 jkunz dma_cmd[0].control = __SHIFTIN(cmd->c_datalen, APBDMA_CMD_XFER_COUNT) |
923 1.3 jkunz __SHIFTIN(3, APBDMA_CMD_CMDPIOWORDS) |
924 1.3 jkunz APBDMA_CMD_HALTONTERMINATE | APBDMA_CMD_WAIT4ENDCMD |
925 1.3 jkunz APBDMA_CMD_SEMAPHORE | APBDMA_CMD_IRQONCMPLT;
926 1.3 jkunz
927 1.3 jkunz /* Transfer single block to the beginning of the DMA buffer. */
928 1.3 jkunz apbdma_cmd_buf(&dma_cmd[0], 0, cmd->c_dmamap);
929 1.3 jkunz
930 1.3 jkunz if (!ISSET(cmd->c_flags, SCF_RSP_CRC)) {
931 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |=
932 1.3 jkunz HW_SSP_CTRL0_IGNORE_CRC;
933 1.3 jkunz }
934 1.3 jkunz
935 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |=
936 1.3 jkunz HW_SSP_CTRL0_DATA_XFER |
937 1.3 jkunz __SHIFTIN(sc->sc_bus_width, HW_SSP_CTRL0_BUS_WIDTH) |
938 1.3 jkunz HW_SSP_CTRL0_WAIT_FOR_IRQ |
939 1.3 jkunz __SHIFTIN(cmd->c_datalen, HW_SSP_CTRL0_XFER_COUNT);
940 1.3 jkunz
941 1.3 jkunz if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
942 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_GET_RESP;
943 1.3 jkunz if (ISSET(cmd->c_flags, SCF_RSP_136)) {
944 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |=
945 1.3 jkunz HW_SSP_CTRL0_LONG_RESP;
946 1.3 jkunz }
947 1.3 jkunz }
948 1.3 jkunz
949 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_ENABLE;
950 1.3 jkunz
951 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CMD0] =
952 1.3 jkunz HW_SSP_CMD0_APPEND_8CYC |
953 1.3 jkunz __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD);
954 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CMD1] = cmd->c_arg;
955 1.3 jkunz
956 1.3 jkunz if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
957 1.3 jkunz dma_cmd[0].control |=
958 1.3 jkunz __SHIFTIN(APBDMA_CMD_DMA_WRITE, APBDMA_CMD_COMMAND);
959 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_READ;
960 1.3 jkunz } else {
961 1.3 jkunz dma_cmd[0].control |=
962 1.3 jkunz __SHIFTIN(APBDMA_CMD_DMA_READ, APBDMA_CMD_COMMAND);
963 1.3 jkunz }
964 1.3 jkunz
965 1.3 jkunz return;
966 1.3 jkunz }
967 1.3 jkunz
968 1.3 jkunz /*
969 1.3 jkunz * Do DMA PIO (issue CMD). No block transfers.
970 1.3 jkunz */
971 1.3 jkunz static void
972 1.3 jkunz issp_create_dma_cmd_list(issp_softc_t sc, void *dma_chain,
973 1.3 jkunz struct sdmmc_command *cmd)
974 1.3 jkunz {
975 1.3 jkunz apbdma_command_t dma_cmd;
976 1.3 jkunz
977 1.3 jkunz dma_cmd = dma_chain;
978 1.3 jkunz
979 1.3 jkunz dma_cmd[0].control = __SHIFTIN(3, APBDMA_CMD_CMDPIOWORDS) |
980 1.3 jkunz APBDMA_CMD_HALTONTERMINATE | APBDMA_CMD_WAIT4ENDCMD |
981 1.3 jkunz APBDMA_CMD_SEMAPHORE | APBDMA_CMD_IRQONCMPLT |
982 1.3 jkunz __SHIFTIN(APBDMA_CMD_NO_DMA_XFER, APBDMA_CMD_COMMAND);
983 1.3 jkunz
984 1.3 jkunz if (!ISSET(cmd->c_flags, SCF_RSP_CRC)) {
985 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |=
986 1.3 jkunz HW_SSP_CTRL0_IGNORE_CRC;
987 1.3 jkunz }
988 1.3 jkunz
989 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |=
990 1.3 jkunz __SHIFTIN(sc->sc_bus_width, HW_SSP_CTRL0_BUS_WIDTH) |
991 1.3 jkunz HW_SSP_CTRL0_WAIT_FOR_IRQ;
992 1.3 jkunz
993 1.3 jkunz if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
994 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_GET_RESP;
995 1.3 jkunz if (ISSET(cmd->c_flags, SCF_RSP_136)) {
996 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |=
997 1.3 jkunz HW_SSP_CTRL0_LONG_RESP;
998 1.3 jkunz }
999 1.3 jkunz }
1000 1.3 jkunz
1001 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_ENABLE;
1002 1.3 jkunz
1003 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CMD0] =
1004 1.3 jkunz __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD);
1005 1.3 jkunz dma_cmd[0].pio_words[PIO_WORD_CMD1] = cmd->c_arg;
1006 1.3 jkunz
1007 1.3 jkunz return;
1008 1.3 jkunz }
1009