xref: /netbsd-src/sys/dev/ic/pl181.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /* $NetBSD: pl181.c,v 1.1 2015/01/27 16:33:26 jmcneill Exp $ */
2 
3 /*-
4  * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca>
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,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: pl181.c,v 1.1 2015/01/27 16:33:26 jmcneill Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/device.h>
35 #include <sys/intr.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 
39 #include <dev/sdmmc/sdmmcvar.h>
40 #include <dev/sdmmc/sdmmcchip.h>
41 #include <dev/sdmmc/sdmmc_ioreg.h>
42 
43 #include <dev/ic/pl181reg.h>
44 #include <dev/ic/pl181var.h>
45 
46 static int	plmmc_host_reset(sdmmc_chipset_handle_t);
47 static uint32_t	plmmc_host_ocr(sdmmc_chipset_handle_t);
48 static int	plmmc_host_maxblklen(sdmmc_chipset_handle_t);
49 static int	plmmc_card_detect(sdmmc_chipset_handle_t);
50 static int	plmmc_write_protect(sdmmc_chipset_handle_t);
51 static int	plmmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
52 static int	plmmc_bus_clock(sdmmc_chipset_handle_t, int);
53 static int	plmmc_bus_width(sdmmc_chipset_handle_t, int);
54 static int	plmmc_bus_rod(sdmmc_chipset_handle_t, int);
55 static void	plmmc_exec_command(sdmmc_chipset_handle_t,
56 				     struct sdmmc_command *);
57 static void	plmmc_card_enable_intr(sdmmc_chipset_handle_t, int);
58 static void	plmmc_card_intr_ack(sdmmc_chipset_handle_t);
59 
60 static int	plmmc_wait_status(struct plmmc_softc *, uint32_t, int);
61 static int	plmmc_pio_wait(struct plmmc_softc *,
62 				 struct sdmmc_command *);
63 static int	plmmc_pio_transfer(struct plmmc_softc *,
64 				     struct sdmmc_command *);
65 
66 static struct sdmmc_chip_functions plmmc_chip_functions = {
67 	.host_reset = plmmc_host_reset,
68 	.host_ocr = plmmc_host_ocr,
69 	.host_maxblklen = plmmc_host_maxblklen,
70 	.card_detect = plmmc_card_detect,
71 	.write_protect = plmmc_write_protect,
72 	.bus_power = plmmc_bus_power,
73 	.bus_clock = plmmc_bus_clock,
74 	.bus_width = plmmc_bus_width,
75 	.bus_rod = plmmc_bus_rod,
76 	.exec_command = plmmc_exec_command,
77 	.card_enable_intr = plmmc_card_enable_intr,
78 	.card_intr_ack = plmmc_card_intr_ack,
79 };
80 
81 #define MMCI_WRITE(sc, reg, val) \
82 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
83 #define MMCI_READ(sc, reg) \
84 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
85 
86 void
87 plmmc_init(struct plmmc_softc *sc)
88 {
89 	struct sdmmcbus_attach_args saa;
90 
91 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO);
92 	cv_init(&sc->sc_intr_cv, "plmmcirq");
93 
94 #ifdef PLMMC_DEBUG
95 	device_printf(sc->sc_dev, "PeriphID %#x %#x %#x %#x\n",
96 	    MMCI_READ(sc, MMCI_PERIPH_ID0_REG),
97 	    MMCI_READ(sc, MMCI_PERIPH_ID1_REG),
98 	    MMCI_READ(sc, MMCI_PERIPH_ID2_REG),
99 	    MMCI_READ(sc, MMCI_PERIPH_ID3_REG));
100 	device_printf(sc->sc_dev, "PCellID %#x %#x %#x %#x\n",
101 	    MMCI_READ(sc, MMCI_PCELL_ID0_REG),
102 	    MMCI_READ(sc, MMCI_PCELL_ID1_REG),
103 	    MMCI_READ(sc, MMCI_PCELL_ID2_REG),
104 	    MMCI_READ(sc, MMCI_PCELL_ID3_REG));
105 #endif
106 
107 	plmmc_bus_clock(sc, 400);
108 	MMCI_WRITE(sc, MMCI_POWER_REG, 0);
109 	delay(10000);
110 	MMCI_WRITE(sc, MMCI_POWER_REG, MMCI_POWER_CTRL_POWERUP);
111 	delay(10000);
112 	MMCI_WRITE(sc, MMCI_POWER_REG, MMCI_POWER_CTRL_POWERON);
113 	plmmc_host_reset(sc);
114 
115 	memset(&saa, 0, sizeof(saa));
116 	saa.saa_busname = "sdmmc";
117 	saa.saa_sct = &plmmc_chip_functions;
118 	saa.saa_sch = sc;
119 	saa.saa_clkmin = 400;
120 	saa.saa_clkmax = sc->sc_clock_freq / 1000;
121 	saa.saa_caps = 0;
122 
123 	sc->sc_sdmmc_dev = config_found(sc->sc_dev, &saa, NULL);
124 }
125 
126 int
127 plmmc_intr(void *priv)
128 {
129 	struct plmmc_softc *sc = priv;
130 	uint32_t status;
131 
132 	mutex_enter(&sc->sc_intr_lock);
133 	status = MMCI_READ(sc, MMCI_STATUS_REG);
134 #ifdef PLMMC_DEBUG
135 	printf("%s: MMCI_STATUS_REG = %#x\n", __func__, status);
136 #endif
137 	if (!status) {
138 		mutex_exit(&sc->sc_intr_lock);
139 		return 0;
140 	}
141 
142 	sc->sc_intr_status |= status;
143 	cv_broadcast(&sc->sc_intr_cv);
144 
145 	mutex_exit(&sc->sc_intr_lock);
146 
147 	return 1;
148 }
149 
150 static int
151 plmmc_wait_status(struct plmmc_softc *sc, uint32_t mask, int timeout)
152 {
153 	int retry, error;
154 
155 	KASSERT(mutex_owned(&sc->sc_intr_lock));
156 
157 	if (sc->sc_intr_status & mask)
158 		return 0;
159 
160 	retry = timeout / hz;
161 	if (sc->sc_ih == NULL)
162 		retry *= 1000;
163 
164 	while (retry > 0) {
165 		if (sc->sc_ih == NULL) {
166 			sc->sc_intr_status |= MMCI_READ(sc, MMCI_STATUS_REG);
167 			if (sc->sc_intr_status & mask)
168 				return 0;
169 			delay(10000);
170 		} else {
171 			error = cv_timedwait(&sc->sc_intr_cv,
172 			    &sc->sc_intr_lock, hz);
173 			if (error && error != EWOULDBLOCK) {
174 				device_printf(sc->sc_dev,
175 				    "cv_timedwait returned %d\n", error);
176 				return error;
177 			}
178 			if (sc->sc_intr_status & mask)
179 				return 0;
180 		}
181 		--retry;
182 	}
183 
184 	device_printf(sc->sc_dev, "%s timeout, MMCI_STATUS_REG = %#x\n",
185 	    __func__, MMCI_READ(sc, MMCI_STATUS_REG));
186 
187 	return ETIMEDOUT;
188 }
189 
190 static int
191 plmmc_pio_wait(struct plmmc_softc *sc, struct sdmmc_command *cmd)
192 {
193 	uint32_t bit = (cmd->c_flags & SCF_CMD_READ) ?
194 	    MMCI_INT_RX_DATA_AVAIL : MMCI_INT_TX_FIFO_EMPTY;
195 
196 	MMCI_WRITE(sc, MMCI_CLEAR_REG, bit);
197 	const int error = plmmc_wait_status(sc,
198 		bit | MMCI_INT_DATA_END | MMCI_INT_DATA_BLOCK_END, hz*2);
199 	sc->sc_intr_status &= ~bit;
200 
201 	return error;
202 }
203 
204 static int
205 plmmc_pio_transfer(struct plmmc_softc *sc, struct sdmmc_command *cmd)
206 {
207 	uint32_t *datap = (uint32_t *)cmd->c_data;
208 	int i;
209 
210 	cmd->c_resid = cmd->c_datalen;
211 	for (i = 0; i < (cmd->c_datalen >> 2); i++) {
212 		if (plmmc_pio_wait(sc, cmd))
213 			return ETIMEDOUT;
214 		if (cmd->c_flags & SCF_CMD_READ) {
215 			datap[i] = MMCI_READ(sc, MMCI_FIFO_REG);
216 		} else {
217 			MMCI_WRITE(sc, MMCI_FIFO_REG, datap[i]);
218 		}
219 		cmd->c_resid -= 4;
220 	}
221 
222 	return 0;
223 }
224 
225 static int
226 plmmc_host_reset(sdmmc_chipset_handle_t sch)
227 {
228 	struct plmmc_softc *sc = sch;
229 
230 	MMCI_WRITE(sc, MMCI_MASK0_REG, 0);
231 	MMCI_WRITE(sc, MMCI_MASK1_REG, 0);
232 	MMCI_WRITE(sc, MMCI_CLEAR_REG, 0xffffffff);
233 
234 	return 0;
235 }
236 
237 static uint32_t
238 plmmc_host_ocr(sdmmc_chipset_handle_t sch)
239 {
240 	return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V;
241 }
242 
243 static int
244 plmmc_host_maxblklen(sdmmc_chipset_handle_t sch)
245 {
246 	return 2048;
247 }
248 
249 static int
250 plmmc_card_detect(sdmmc_chipset_handle_t sch)
251 {
252 	return 1;
253 }
254 
255 static int
256 plmmc_write_protect(sdmmc_chipset_handle_t sch)
257 {
258 	return 0;
259 }
260 
261 static int
262 plmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
263 {
264 	return 0;
265 }
266 
267 static int
268 plmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
269 {
270 	struct plmmc_softc *sc = sch;
271 	u_int pll_freq, clk_div;
272 	uint32_t clock;
273 
274 	clock = MMCI_CLOCK_PWRSAVE;
275 	if (freq) {
276 		pll_freq = sc->sc_clock_freq / 1000;
277 		clk_div = (howmany(pll_freq, freq) >> 1) - 1;
278 		clock |= __SHIFTIN(clk_div, MMCI_CLOCK_CLKDIV);
279 		clock |= MMCI_CLOCK_ENABLE;
280 	}
281 	MMCI_WRITE(sc, MMCI_CLOCK_REG, clock);
282 
283 	return 0;
284 }
285 
286 static int
287 plmmc_bus_width(sdmmc_chipset_handle_t sch, int width)
288 {
289 	return 0;
290 }
291 
292 static int
293 plmmc_bus_rod(sdmmc_chipset_handle_t sch, int on)
294 {
295 	struct plmmc_softc *sc = sch;
296 	uint32_t power;
297 
298 
299 	power = MMCI_READ(sc, MMCI_POWER_REG);
300 	if (on) {
301 		power |= MMCI_POWER_ROD;
302 	} else {
303 		power &= ~MMCI_POWER_ROD;
304 	}
305 	MMCI_WRITE(sc, MMCI_POWER_REG, power);
306 
307 	return 0;
308 }
309 
310 static void
311 plmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
312 {
313 	struct plmmc_softc *sc = sch;
314 	uint32_t cmdval = MMCI_COMMAND_ENABLE;
315 
316 #ifdef PLMMC_DEBUG
317 	device_printf(sc->sc_dev, "opcode %d flags %#x datalen %d\n",
318 	    cmd->c_opcode, cmd->c_flags, cmd->c_datalen);
319 #endif
320 
321 	mutex_enter(&sc->sc_intr_lock);
322 
323 	MMCI_WRITE(sc, MMCI_COMMAND_REG, 0);
324 	MMCI_WRITE(sc, MMCI_MASK0_REG, 0);
325 	MMCI_WRITE(sc, MMCI_CLEAR_REG, 0xffffffff);
326 	MMCI_WRITE(sc, MMCI_MASK0_REG,
327 	    MMCI_INT_CMD_TIMEOUT | MMCI_INT_DATA_TIMEOUT |
328 	    MMCI_INT_RX_DATA_AVAIL | MMCI_INT_TX_FIFO_EMPTY |
329 	    MMCI_INT_DATA_END | MMCI_INT_DATA_BLOCK_END |
330 	    MMCI_INT_CMD_RESP_END | MMCI_INT_CMD_SENT);
331 
332 	sc->sc_intr_status = 0;
333 
334 	if (cmd->c_flags & SCF_RSP_PRESENT)
335 		cmdval |= MMCI_COMMAND_RESPONSE;
336 	if (cmd->c_flags & SCF_RSP_136)
337 		cmdval |= MMCI_COMMAND_LONGRSP;
338 
339 	if (cmd->c_datalen > 0) {
340 		unsigned int nblks = cmd->c_datalen / cmd->c_blklen;
341 		if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0)
342 			++nblks;
343 
344 		const uint32_t dir = (cmd->c_flags & SCF_CMD_READ) ? 1 : 0;
345 		const uint32_t blksize = ffs(cmd->c_blklen) - 1;
346 
347 		MMCI_WRITE(sc, MMCI_DATA_TIMER_REG, 0xffffffff);
348 		MMCI_WRITE(sc, MMCI_DATA_LENGTH_REG, nblks * cmd->c_blklen);
349 		MMCI_WRITE(sc, MMCI_DATA_CTRL_REG,
350 		    __SHIFTIN(dir, MMCI_DATA_CTRL_DIRECTION) |
351 		    __SHIFTIN(blksize, MMCI_DATA_CTRL_BLOCKSIZE) |
352 		    MMCI_DATA_CTRL_ENABLE);
353 	}
354 
355 	MMCI_WRITE(sc, MMCI_ARGUMENT_REG, cmd->c_arg);
356 	MMCI_WRITE(sc, MMCI_COMMAND_REG, cmdval | cmd->c_opcode);
357 
358 	if (cmd->c_datalen > 0) {
359 		cmd->c_error = plmmc_pio_transfer(sc, cmd);
360 		if (cmd->c_error) {
361 			device_printf(sc->sc_dev,
362 			    "error (%d) waiting for xfer\n", cmd->c_error);
363 			goto done;
364 		}
365 	}
366 
367 	if (cmd->c_flags & SCF_RSP_PRESENT) {
368 		cmd->c_error = plmmc_wait_status(sc,
369 		    MMCI_INT_CMD_RESP_END|MMCI_INT_CMD_TIMEOUT, hz * 2);
370 		if (cmd->c_error == 0 &&
371 		    (sc->sc_intr_status & MMCI_INT_CMD_TIMEOUT)) {
372 			cmd->c_error = ETIMEDOUT;
373 		}
374 		if (cmd->c_error) {
375 #ifdef PLMMC_DEBUG
376 			device_printf(sc->sc_dev,
377 			    "error (%d) waiting for resp\n", cmd->c_error);
378 #endif
379 			goto done;
380 		}
381 
382 		if (cmd->c_flags & SCF_RSP_136) {
383 			cmd->c_resp[3] = MMCI_READ(sc, MMCI_RESP0_REG);
384 			cmd->c_resp[2] = MMCI_READ(sc, MMCI_RESP1_REG);
385 			cmd->c_resp[1] = MMCI_READ(sc, MMCI_RESP2_REG);
386 			cmd->c_resp[0] = MMCI_READ(sc, MMCI_RESP3_REG);
387 			if (cmd->c_flags & SCF_RSP_CRC) {
388 				cmd->c_resp[0] = (cmd->c_resp[0] >> 8) |
389 				    (cmd->c_resp[1] << 24);
390 				cmd->c_resp[1] = (cmd->c_resp[1] >> 8) |
391 				    (cmd->c_resp[2] << 24);
392 				cmd->c_resp[2] = (cmd->c_resp[2] >> 8) |
393 				    (cmd->c_resp[3] << 24);
394 				cmd->c_resp[3] = (cmd->c_resp[3] >> 8);
395 			}
396 		} else {
397 			cmd->c_resp[0] = MMCI_READ(sc, MMCI_RESP0_REG);
398 		}
399 	}
400 
401 done:
402 	cmd->c_flags |= SCF_ITSDONE;
403 	MMCI_WRITE(sc, MMCI_COMMAND_REG, 0);
404 	MMCI_WRITE(sc, MMCI_MASK0_REG, 0);
405 	MMCI_WRITE(sc, MMCI_CLEAR_REG, 0xffffffff);
406 	MMCI_WRITE(sc, MMCI_DATA_CNT_REG, 0);
407 
408 #ifdef PLMMC_DEBUG
409 	device_printf(sc->sc_dev, "MMCI_STATUS_REG = %#x\n",
410 	    MMCI_READ(sc, MMCI_STATUS_REG));
411 #endif
412 	mutex_exit(&sc->sc_intr_lock);
413 }
414 
415 static void
416 plmmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable)
417 {
418 }
419 
420 static void
421 plmmc_card_intr_ack(sdmmc_chipset_handle_t sch)
422 {
423 }
424