xref: /openbsd/sys/dev/fdt/dwmmc.c (revision 24225f53)
1*24225f53Skettenis /*	$OpenBSD: dwmmc.c,v 1.1 2017/05/21 08:59:45 kettenis Exp $	*/
2*24225f53Skettenis /*
3*24225f53Skettenis  * Copyright (c) 2017 Mark Kettenis
4*24225f53Skettenis  *
5*24225f53Skettenis  * Permission to use, copy, modify, and distribute this software for any
6*24225f53Skettenis  * purpose with or without fee is hereby granted, provided that the above
7*24225f53Skettenis  * copyright notice and this permission notice appear in all copies.
8*24225f53Skettenis  *
9*24225f53Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*24225f53Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*24225f53Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*24225f53Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*24225f53Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*24225f53Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*24225f53Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*24225f53Skettenis  */
17*24225f53Skettenis 
18*24225f53Skettenis #include <sys/param.h>
19*24225f53Skettenis #include <sys/malloc.h>
20*24225f53Skettenis #include <sys/systm.h>
21*24225f53Skettenis 
22*24225f53Skettenis #include <machine/bus.h>
23*24225f53Skettenis #include <machine/fdt.h>
24*24225f53Skettenis #include <machine/intr.h>
25*24225f53Skettenis 
26*24225f53Skettenis #include <dev/ofw/openfirm.h>
27*24225f53Skettenis #include <dev/ofw/ofw_clock.h>
28*24225f53Skettenis #include <dev/ofw/ofw_pinctrl.h>
29*24225f53Skettenis #include <dev/ofw/fdt.h>
30*24225f53Skettenis 
31*24225f53Skettenis #include <dev/sdmmc/sdmmcvar.h>
32*24225f53Skettenis 
33*24225f53Skettenis #define SDMMC_CTRL		0x0000
34*24225f53Skettenis #define  SDMMC_CTRL_USE_INTERNAL_DMAC	(1 << 25)
35*24225f53Skettenis #define  SDMMC_CTRL_DMA_RESET		(1 << 3)
36*24225f53Skettenis #define  SDMMC_CTRL_FIFO_RESET		(1 << 2)
37*24225f53Skettenis #define  SDMMC_CTRL_CONTROLLER_RESET	(1 << 3)
38*24225f53Skettenis #define  SDMMC_CTRL_ALL_RESET	(SDMMC_CTRL_CONTROLLER_RESET | \
39*24225f53Skettenis     SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)
40*24225f53Skettenis #define SDMMC_PWREN		0x0004
41*24225f53Skettenis #define SDMMC_CLKDIV		0x0008
42*24225f53Skettenis #define SDMMC_CLKSRC		0x000c
43*24225f53Skettenis #define SDMMC_CLKENA		0x0010
44*24225f53Skettenis #define  SDMMC_CLKENA_CCLK_LOW_POWER	(1 << 16)
45*24225f53Skettenis #define  SDMMC_CLKENA_CCLK_ENABLE	(1 << 0)
46*24225f53Skettenis #define SDMMC_TMOUT		0x0014
47*24225f53Skettenis #define SDMMC_CTYPE		0x0018
48*24225f53Skettenis #define  SDMMC_CTYPE_8BIT		(1 << 16)
49*24225f53Skettenis #define  SDMMC_CTYPE_4BIT		(1 << 0)
50*24225f53Skettenis #define SDMMC_BLKSIZ		0x001c
51*24225f53Skettenis #define SDMMC_BYTCNT		0x0020
52*24225f53Skettenis #define SDMMC_INTMASK		0x0024
53*24225f53Skettenis #define SDMMC_CMDARG		0x0028
54*24225f53Skettenis #define SDMMC_CMD		0x002c
55*24225f53Skettenis #define  SDMMC_CMD_START_CMD		(1U << 31)
56*24225f53Skettenis #define  SDMMC_CMD_USE_HOLD_REG		(1 << 29)
57*24225f53Skettenis #define  SDMMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY	(1 << 21)
58*24225f53Skettenis #define  SDMMC_CMD_SEND_INITIALIZATION	(1 << 15)
59*24225f53Skettenis #define  SDMMC_CMD_STOP_ABORT_CMD	(1 << 14)
60*24225f53Skettenis #define  SDMMC_CMD_WAIT_PRVDATA_COMPLETE	(1 << 13)
61*24225f53Skettenis #define  SDMMC_CMD_SEND_AUTO_STOP	(1 << 12)
62*24225f53Skettenis #define  SDMMC_CMD_WR			(1 << 10)
63*24225f53Skettenis #define  SDMMC_CMD_DATA_EXPECTED	(1 << 9)
64*24225f53Skettenis #define  SDMMC_CMD_CHECK_REPONSE_CRC	(1 << 8)
65*24225f53Skettenis #define  SDMMC_CMD_RESPONSE_LENGTH	(1 << 7)
66*24225f53Skettenis #define  SDMMC_CMD_RESPONSE_EXPECT	(1 << 6)
67*24225f53Skettenis #define SDMMC_RESP0		0x0030
68*24225f53Skettenis #define SDMMC_RESP1		0x0034
69*24225f53Skettenis #define SDMMC_RESP2		0x0038
70*24225f53Skettenis #define SDMMC_RESP3		0x003c
71*24225f53Skettenis #define SDMMC_MINTSTS		0x0040
72*24225f53Skettenis #define SDMMC_RINTSTS		0x0044
73*24225f53Skettenis #define  SDMMC_RINTSTS_EBE		(1 << 15)
74*24225f53Skettenis #define  SDMMC_RINTSTS_ACD		(1 << 14)
75*24225f53Skettenis #define  SDMMC_RINTSTS_SBE		(1 << 13)
76*24225f53Skettenis #define  SDMMC_RINTSTS_HLE		(1 << 12)
77*24225f53Skettenis #define  SDMMC_RINTSTS_FRUN		(1 << 11)
78*24225f53Skettenis #define  SDMMC_RINTSTS_HTO		(1 << 10)
79*24225f53Skettenis #define  SDMMC_RINTSTS_DRTO		(1 << 9)
80*24225f53Skettenis #define  SDMMC_RINTSTS_RTO		(1 << 8)
81*24225f53Skettenis #define  SDMMC_RINTSTS_DCRC		(1 << 7)
82*24225f53Skettenis #define  SDMMC_RINTSTS_RCRC		(1 << 6)
83*24225f53Skettenis #define  SDMMC_RINTSTS_RXDR		(1 << 5)
84*24225f53Skettenis #define  SDMMC_RINTSTS_TXDR		(1 << 4)
85*24225f53Skettenis #define  SDMMC_RINTSTS_DTO		(1 << 3)
86*24225f53Skettenis #define  SDMMC_RINTSTS_CD		(1 << 2)
87*24225f53Skettenis #define  SDMMC_RINTSTS_RE		(1 << 1)
88*24225f53Skettenis #define  SDMMC_RINTSTS_CDT		(1 << 0)
89*24225f53Skettenis #define  SDMMC_RINTSTS_DATA_ERR	(SDMMC_RINTSTS_EBE | SDMMC_RINTSTS_SBE | \
90*24225f53Skettenis      SDMMC_RINTSTS_HLE | SDMMC_RINTSTS_FRUN | SDMMC_RINTSTS_DCRC)
91*24225f53Skettenis #define  SDMMC_RINTSTS_DATA_TO	(SDMMC_RINTSTS_HTO | SDMMC_RINTSTS_DRTO)
92*24225f53Skettenis #define SDMMC_STATUS		0x0048
93*24225f53Skettenis #define SDMMC_STATUS_FIFO_COUNT(x)	(((x) >> 17) & 0x1fff)
94*24225f53Skettenis #define  SDMMC_STATUS_DATA_BUSY		(1 << 9)
95*24225f53Skettenis #define SDMMC_FIFOTH		0x004c
96*24225f53Skettenis #define SDMMC_CDETECT		0x0050
97*24225f53Skettenis #define  SDMMC_CDETECT_CARD_DETECT_0	(1 << 0)
98*24225f53Skettenis #define SDMMC_WRTPRT		0x0054
99*24225f53Skettenis #define SDMMC_TCBCNT		0x005c
100*24225f53Skettenis #define SDMMC_TBBCNT		0x0060
101*24225f53Skettenis #define SDMMC_DEBNCE		0x0064
102*24225f53Skettenis #define SDMMC_USRID		0x0068
103*24225f53Skettenis #define SDMMC_VERID		0x006c
104*24225f53Skettenis #define SDMMC_HCON		0x0070
105*24225f53Skettenis #define SDMMC_UHS_REG		0x0074
106*24225f53Skettenis #define SDMMC_RST_n		0x0078
107*24225f53Skettenis #define SDMMC_BMOD		0x0080
108*24225f53Skettenis #define SDMMC_PLDMND		0x0084
109*24225f53Skettenis #define SDMMC_DBADDR		0x0088
110*24225f53Skettenis #define SDMMC_IDSTS		0x008c
111*24225f53Skettenis #define SDMMC_IDINTEN		0x0090
112*24225f53Skettenis #define SDMMC_DSCADDR		0x0094
113*24225f53Skettenis #define SDMMC_BUFADDR		0x0098
114*24225f53Skettenis #define SDMMC_CARDTHRCTL	0x0100
115*24225f53Skettenis #define  SDMMC_CARDTHRCTL_RDTHR_SHIFT	16
116*24225f53Skettenis #define  SDMMC_CARDTHRCTL_RDTHREN	(1 << 0)
117*24225f53Skettenis #define SDMMC_BACK_END_POWER	0x0104
118*24225f53Skettenis #define SDMMC_EMMC_DDR_REG	0x0108
119*24225f53Skettenis #define SDMMC_FIFO_BASE		0x0200
120*24225f53Skettenis 
121*24225f53Skettenis #define HREAD4(sc, reg)							\
122*24225f53Skettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
123*24225f53Skettenis #define HWRITE4(sc, reg, val)						\
124*24225f53Skettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
125*24225f53Skettenis #define HSET4(sc, reg, bits)						\
126*24225f53Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
127*24225f53Skettenis #define HCLR4(sc, reg, bits)						\
128*24225f53Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
129*24225f53Skettenis 
130*24225f53Skettenis struct dwmmc_softc {
131*24225f53Skettenis 	struct device		sc_dev;
132*24225f53Skettenis 	bus_space_tag_t		sc_iot;
133*24225f53Skettenis 	bus_space_handle_t	sc_ioh;
134*24225f53Skettenis 	bus_size_t		sc_size;
135*24225f53Skettenis 	void			*sc_ih;
136*24225f53Skettenis 
137*24225f53Skettenis 	uint32_t		sc_clkbase;
138*24225f53Skettenis 	uint32_t		sc_fifo_depth;
139*24225f53Skettenis 
140*24225f53Skettenis 	struct device		*sc_sdmmc;
141*24225f53Skettenis };
142*24225f53Skettenis 
143*24225f53Skettenis int	dwmmc_match(struct device *, void *, void *);
144*24225f53Skettenis void	dwmmc_attach(struct device *, struct device *, void *);
145*24225f53Skettenis 
146*24225f53Skettenis struct cfattach dwmmc_ca = {
147*24225f53Skettenis 	sizeof(struct dwmmc_softc), dwmmc_match, dwmmc_attach
148*24225f53Skettenis };
149*24225f53Skettenis 
150*24225f53Skettenis struct cfdriver dwmmc_cd = {
151*24225f53Skettenis 	NULL, "dwmmc", DV_DULL
152*24225f53Skettenis };
153*24225f53Skettenis 
154*24225f53Skettenis int	dwmmc_intr(void *);
155*24225f53Skettenis 
156*24225f53Skettenis int	dwmmc_host_reset(sdmmc_chipset_handle_t);
157*24225f53Skettenis uint32_t dwmmc_host_ocr(sdmmc_chipset_handle_t);
158*24225f53Skettenis int	dwmmc_host_maxblklen(sdmmc_chipset_handle_t);
159*24225f53Skettenis int	dwmmc_card_detect(sdmmc_chipset_handle_t);
160*24225f53Skettenis int	dwmmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
161*24225f53Skettenis int	dwmmc_bus_clock(sdmmc_chipset_handle_t, int, int);
162*24225f53Skettenis int	dwmmc_bus_width(sdmmc_chipset_handle_t, int);
163*24225f53Skettenis void	dwmmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
164*24225f53Skettenis 
165*24225f53Skettenis struct sdmmc_chip_functions dwmmc_chip_functions = {
166*24225f53Skettenis 	.host_reset = dwmmc_host_reset,
167*24225f53Skettenis 	.host_ocr = dwmmc_host_ocr,
168*24225f53Skettenis 	.host_maxblklen = dwmmc_host_maxblklen,
169*24225f53Skettenis 	.card_detect = dwmmc_card_detect,
170*24225f53Skettenis 	.bus_power = dwmmc_bus_power,
171*24225f53Skettenis 	.bus_clock = dwmmc_bus_clock,
172*24225f53Skettenis 	.bus_width = dwmmc_bus_width,
173*24225f53Skettenis 	.exec_command = dwmmc_exec_command,
174*24225f53Skettenis };
175*24225f53Skettenis 
176*24225f53Skettenis void	dwmmc_transfer_data(struct dwmmc_softc *, struct sdmmc_command *);
177*24225f53Skettenis void	dwmmc_read_data(struct dwmmc_softc *, u_char *, int);
178*24225f53Skettenis void	dwmmc_write_data(struct dwmmc_softc *, u_char *, int);
179*24225f53Skettenis 
180*24225f53Skettenis int
181*24225f53Skettenis dwmmc_match(struct device *parent, void *match, void *aux)
182*24225f53Skettenis {
183*24225f53Skettenis 	struct fdt_attach_args *faa = aux;
184*24225f53Skettenis 
185*24225f53Skettenis 	return OF_is_compatible(faa->fa_node, "rockchip,rk3288-dw-mshc");
186*24225f53Skettenis }
187*24225f53Skettenis 
188*24225f53Skettenis void
189*24225f53Skettenis dwmmc_attach(struct device *parent, struct device *self, void *aux)
190*24225f53Skettenis {
191*24225f53Skettenis 	struct dwmmc_softc *sc = (struct dwmmc_softc *)self;
192*24225f53Skettenis 	struct fdt_attach_args *faa = aux;
193*24225f53Skettenis 	struct sdmmcbus_attach_args saa;
194*24225f53Skettenis 	int timeout;
195*24225f53Skettenis 	int width;
196*24225f53Skettenis 
197*24225f53Skettenis 	if (faa->fa_nreg < 1) {
198*24225f53Skettenis 		printf(": no registers\n");
199*24225f53Skettenis 		return;
200*24225f53Skettenis 	}
201*24225f53Skettenis 
202*24225f53Skettenis 	sc->sc_iot = faa->fa_iot;
203*24225f53Skettenis 	sc->sc_size = faa->fa_reg[0].size;
204*24225f53Skettenis 
205*24225f53Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
206*24225f53Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
207*24225f53Skettenis 		printf(": can't map registers\n");
208*24225f53Skettenis 		return;
209*24225f53Skettenis 	}
210*24225f53Skettenis 
211*24225f53Skettenis 	pinctrl_byname(faa->fa_node, "default");
212*24225f53Skettenis 
213*24225f53Skettenis 	clock_enable_all(faa->fa_node);
214*24225f53Skettenis 	reset_deassert_all(faa->fa_node);
215*24225f53Skettenis 
216*24225f53Skettenis 	sc->sc_clkbase = clock_get_frequency(faa->fa_node, "ciu");
217*24225f53Skettenis 	sc->sc_fifo_depth = OF_getpropint(faa->fa_node, "fifo-depth", 64);
218*24225f53Skettenis 
219*24225f53Skettenis 	sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
220*24225f53Skettenis 	    dwmmc_intr, sc, sc->sc_dev.dv_xname);
221*24225f53Skettenis 	if (sc->sc_ih == NULL) {
222*24225f53Skettenis 		printf(": can't establish interrupt\n");
223*24225f53Skettenis 		goto unmap;
224*24225f53Skettenis 	}
225*24225f53Skettenis 
226*24225f53Skettenis 	printf("\n");
227*24225f53Skettenis 
228*24225f53Skettenis 	HSET4(sc, SDMMC_CTRL, SDMMC_CTRL_ALL_RESET);
229*24225f53Skettenis 	for (timeout = 10000; timeout > 0; timeout--) {
230*24225f53Skettenis 		if ((HREAD4(sc, SDMMC_CTRL) & SDMMC_CTRL_ALL_RESET) == 0)
231*24225f53Skettenis 			break;
232*24225f53Skettenis 		delay(10);
233*24225f53Skettenis 	}
234*24225f53Skettenis 	if (timeout == 0)
235*24225f53Skettenis 		printf("%s: reset failed\n", sc->sc_dev.dv_xname);
236*24225f53Skettenis 
237*24225f53Skettenis 	/* We don't do DMA yet. */
238*24225f53Skettenis 	HCLR4(sc, SDMMC_CTRL, SDMMC_CTRL_USE_INTERNAL_DMAC);
239*24225f53Skettenis 
240*24225f53Skettenis 	/* Set card read threshold to the size of a block. */
241*24225f53Skettenis 	HWRITE4(sc, SDMMC_CARDTHRCTL,
242*24225f53Skettenis 	    512 << SDMMC_CARDTHRCTL_RDTHR_SHIFT | SDMMC_CARDTHRCTL_RDTHREN);
243*24225f53Skettenis 
244*24225f53Skettenis 	dwmmc_bus_width(sc, 1);
245*24225f53Skettenis 
246*24225f53Skettenis 	memset(&saa, 0, sizeof(saa));
247*24225f53Skettenis 	saa.saa_busname = "sdmmc";
248*24225f53Skettenis 	saa.sct = &dwmmc_chip_functions;
249*24225f53Skettenis 	saa.sch = sc;
250*24225f53Skettenis 
251*24225f53Skettenis 	width = OF_getpropint(faa->fa_node, "bus-width", 1);
252*24225f53Skettenis 	if (width >= 8)
253*24225f53Skettenis 		saa.caps |= SMC_CAPS_8BIT_MODE;
254*24225f53Skettenis 	if (width >= 4)
255*24225f53Skettenis 		saa.caps |= SMC_CAPS_4BIT_MODE;
256*24225f53Skettenis 
257*24225f53Skettenis 	sc->sc_sdmmc = config_found(self, &saa, NULL);
258*24225f53Skettenis 	return;
259*24225f53Skettenis 
260*24225f53Skettenis unmap:
261*24225f53Skettenis 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
262*24225f53Skettenis }
263*24225f53Skettenis 
264*24225f53Skettenis int
265*24225f53Skettenis dwmmc_intr(void *arg)
266*24225f53Skettenis {
267*24225f53Skettenis 	return 1;
268*24225f53Skettenis }
269*24225f53Skettenis 
270*24225f53Skettenis int
271*24225f53Skettenis dwmmc_host_reset(sdmmc_chipset_handle_t sch)
272*24225f53Skettenis {
273*24225f53Skettenis 	printf("%s\n", __func__);
274*24225f53Skettenis 	return 0;
275*24225f53Skettenis }
276*24225f53Skettenis 
277*24225f53Skettenis uint32_t
278*24225f53Skettenis dwmmc_host_ocr(sdmmc_chipset_handle_t sch)
279*24225f53Skettenis {
280*24225f53Skettenis 	return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V;
281*24225f53Skettenis }
282*24225f53Skettenis 
283*24225f53Skettenis int
284*24225f53Skettenis dwmmc_host_maxblklen(sdmmc_chipset_handle_t sch)
285*24225f53Skettenis {
286*24225f53Skettenis 	return 512;
287*24225f53Skettenis }
288*24225f53Skettenis 
289*24225f53Skettenis int
290*24225f53Skettenis dwmmc_card_detect(sdmmc_chipset_handle_t sch)
291*24225f53Skettenis {
292*24225f53Skettenis 	struct dwmmc_softc *sc = sch;
293*24225f53Skettenis 	uint32_t cdetect;
294*24225f53Skettenis 
295*24225f53Skettenis 	cdetect = HREAD4(sc, SDMMC_CDETECT);
296*24225f53Skettenis 	return !(cdetect & SDMMC_CDETECT_CARD_DETECT_0);
297*24225f53Skettenis }
298*24225f53Skettenis 
299*24225f53Skettenis int
300*24225f53Skettenis dwmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
301*24225f53Skettenis {
302*24225f53Skettenis 	struct dwmmc_softc *sc = sch;
303*24225f53Skettenis 
304*24225f53Skettenis 	printf("%s: ocr 0x%08x\n", sc->sc_dev.dv_xname, ocr);
305*24225f53Skettenis 
306*24225f53Skettenis 	if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V))
307*24225f53Skettenis 		HSET4(sc, SDMMC_PWREN, 1);
308*24225f53Skettenis 	else
309*24225f53Skettenis 		HCLR4(sc, SDMMC_PWREN, 0);
310*24225f53Skettenis 
311*24225f53Skettenis 	return 0;
312*24225f53Skettenis }
313*24225f53Skettenis 
314*24225f53Skettenis int
315*24225f53Skettenis dwmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing)
316*24225f53Skettenis {
317*24225f53Skettenis 	struct dwmmc_softc *sc = sch;
318*24225f53Skettenis 	int div = 0, timeout;
319*24225f53Skettenis 
320*24225f53Skettenis 	printf("%s: freq %d timing %d\n", sc->sc_dev.dv_xname, freq, timing);
321*24225f53Skettenis 
322*24225f53Skettenis 	HWRITE4(sc, SDMMC_CLKENA, 0);
323*24225f53Skettenis 	HWRITE4(sc, SDMMC_CLKSRC, 0);
324*24225f53Skettenis 
325*24225f53Skettenis 	if (freq == 0)
326*24225f53Skettenis 		return 0;
327*24225f53Skettenis 
328*24225f53Skettenis 	if (sc->sc_clkbase / 1000 > freq) {
329*24225f53Skettenis 		for (div = 1; div < 256; div++)
330*24225f53Skettenis 			if (sc->sc_clkbase / (2 * 1000 * div) <= freq)
331*24225f53Skettenis 				break;
332*24225f53Skettenis 	}
333*24225f53Skettenis 	printf("%s: div %d\n", sc->sc_dev.dv_xname, div);
334*24225f53Skettenis 	HWRITE4(sc, SDMMC_CLKDIV, div);
335*24225f53Skettenis 
336*24225f53Skettenis 	/* Update clock. */
337*24225f53Skettenis 	HWRITE4(sc, SDMMC_CMD, SDMMC_CMD_START_CMD |
338*24225f53Skettenis 	    SDMMC_CMD_WAIT_PRVDATA_COMPLETE |
339*24225f53Skettenis 	    SDMMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY);
340*24225f53Skettenis 	for (timeout = 1000; timeout > 0; timeout--) {
341*24225f53Skettenis 		if ((HREAD4(sc, SDMMC_CMD) & SDMMC_CMD_START_CMD) == 0)
342*24225f53Skettenis 			break;
343*24225f53Skettenis 	}
344*24225f53Skettenis 	if (timeout == 0) {
345*24225f53Skettenis 		printf("%s: timeout\n", __func__);
346*24225f53Skettenis 		return ETIMEDOUT;
347*24225f53Skettenis 	}
348*24225f53Skettenis 
349*24225f53Skettenis 	/* Enable clock in low power mode. */
350*24225f53Skettenis 	HWRITE4(sc, SDMMC_CLKENA,
351*24225f53Skettenis 	    SDMMC_CLKENA_CCLK_ENABLE | SDMMC_CLKENA_CCLK_LOW_POWER);
352*24225f53Skettenis 
353*24225f53Skettenis 	/* Update clock again. */
354*24225f53Skettenis 	HWRITE4(sc, SDMMC_CMD, SDMMC_CMD_START_CMD |
355*24225f53Skettenis 	    SDMMC_CMD_WAIT_PRVDATA_COMPLETE |
356*24225f53Skettenis 	    SDMMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY);
357*24225f53Skettenis 	for (timeout = 1000; timeout > 0; timeout--) {
358*24225f53Skettenis 		if ((HREAD4(sc, SDMMC_CMD) & SDMMC_CMD_START_CMD) == 0)
359*24225f53Skettenis 			break;
360*24225f53Skettenis 	}
361*24225f53Skettenis 	if (timeout == 0) {
362*24225f53Skettenis 		printf("%s: timeout\n", __func__);
363*24225f53Skettenis 		return ETIMEDOUT;
364*24225f53Skettenis 	}
365*24225f53Skettenis 
366*24225f53Skettenis 	delay(1000000);
367*24225f53Skettenis 
368*24225f53Skettenis 	return 0;
369*24225f53Skettenis }
370*24225f53Skettenis 
371*24225f53Skettenis int
372*24225f53Skettenis dwmmc_bus_width(sdmmc_chipset_handle_t sch, int width)
373*24225f53Skettenis {
374*24225f53Skettenis 	struct dwmmc_softc *sc = sch;
375*24225f53Skettenis 
376*24225f53Skettenis 	printf("%s: width %d\n", sc->sc_dev.dv_xname, width);
377*24225f53Skettenis 
378*24225f53Skettenis 	switch (width) {
379*24225f53Skettenis 	case 1:
380*24225f53Skettenis 		HCLR4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT|SDMMC_CTYPE_4BIT);
381*24225f53Skettenis 		break;
382*24225f53Skettenis 	case 4:
383*24225f53Skettenis 		HSET4(sc, SDMMC_CTYPE, SDMMC_CTYPE_4BIT);
384*24225f53Skettenis 		HCLR4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT);
385*24225f53Skettenis 		break;
386*24225f53Skettenis 	case 8:
387*24225f53Skettenis 		HSET4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT);
388*24225f53Skettenis 		break;
389*24225f53Skettenis 	default:
390*24225f53Skettenis 		return EINVAL;
391*24225f53Skettenis 	}
392*24225f53Skettenis 
393*24225f53Skettenis 	return 0;
394*24225f53Skettenis }
395*24225f53Skettenis 
396*24225f53Skettenis void
397*24225f53Skettenis dwmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
398*24225f53Skettenis {
399*24225f53Skettenis 	struct dwmmc_softc *sc = sch;
400*24225f53Skettenis 	uint32_t cmdval = SDMMC_CMD_START_CMD | SDMMC_CMD_USE_HOLD_REG;
401*24225f53Skettenis 	uint32_t status;
402*24225f53Skettenis 	int timeout;
403*24225f53Skettenis 	int s;
404*24225f53Skettenis 
405*24225f53Skettenis #if 0
406*24225f53Skettenis 	printf("%s: cmd %d arg 0x%x flags 0x%x data %p datalen %d blklen %d\n",
407*24225f53Skettenis 	    sc->sc_dev.dv_xname, cmd->c_opcode, cmd->c_arg, cmd->c_flags,
408*24225f53Skettenis 	    cmd->c_data, cmd->c_datalen, cmd->c_blklen);
409*24225f53Skettenis #endif
410*24225f53Skettenis 
411*24225f53Skettenis 	s = splbio();
412*24225f53Skettenis 
413*24225f53Skettenis 	for (timeout = 1000; timeout > 0; timeout--) {
414*24225f53Skettenis 		status = HREAD4(sc, SDMMC_STATUS);
415*24225f53Skettenis 		if ((status & SDMMC_STATUS_DATA_BUSY) == 0)
416*24225f53Skettenis 			break;
417*24225f53Skettenis 		delay(100);
418*24225f53Skettenis 	}
419*24225f53Skettenis 	if (timeout == 0) {
420*24225f53Skettenis 		printf("%s: timeout on data busy\n", sc->sc_dev.dv_xname);
421*24225f53Skettenis 		goto done;
422*24225f53Skettenis 	}
423*24225f53Skettenis 
424*24225f53Skettenis 	if (cmd->c_opcode == MMC_STOP_TRANSMISSION)
425*24225f53Skettenis 		cmdval |= SDMMC_CMD_STOP_ABORT_CMD;
426*24225f53Skettenis 	else if (cmd->c_opcode != MMC_SEND_STATUS)
427*24225f53Skettenis 		cmdval |= SDMMC_CMD_WAIT_PRVDATA_COMPLETE;
428*24225f53Skettenis 
429*24225f53Skettenis 	if (cmd->c_opcode == MMC_READ_BLOCK_MULTIPLE ||
430*24225f53Skettenis 	    cmd->c_opcode == MMC_WRITE_BLOCK_MULTIPLE)
431*24225f53Skettenis 		cmdval |= SDMMC_CMD_SEND_AUTO_STOP;
432*24225f53Skettenis 
433*24225f53Skettenis 	if (cmd->c_opcode == 0)
434*24225f53Skettenis 		cmdval |= SDMMC_CMD_SEND_INITIALIZATION;
435*24225f53Skettenis 	if (cmd->c_flags & SCF_RSP_PRESENT)
436*24225f53Skettenis 		cmdval |= SDMMC_CMD_RESPONSE_EXPECT;
437*24225f53Skettenis 	if (cmd->c_flags & SCF_RSP_136)
438*24225f53Skettenis 		cmdval |= SDMMC_CMD_RESPONSE_LENGTH;
439*24225f53Skettenis 	if (cmd->c_flags & SCF_RSP_CRC)
440*24225f53Skettenis 		cmdval |= SDMMC_CMD_CHECK_REPONSE_CRC;
441*24225f53Skettenis 
442*24225f53Skettenis 	if (cmd->c_datalen > 0) {
443*24225f53Skettenis 		HWRITE4(sc, SDMMC_TMOUT, 0xffffffff);
444*24225f53Skettenis 		HWRITE4(sc, SDMMC_BYTCNT, cmd->c_datalen);
445*24225f53Skettenis 		HWRITE4(sc, SDMMC_BLKSIZ, cmd->c_blklen);
446*24225f53Skettenis 
447*24225f53Skettenis 		HSET4(sc, SDMMC_CTRL, SDMMC_CTRL_FIFO_RESET);
448*24225f53Skettenis 		for (timeout = 1000; timeout > 0; timeout--) {
449*24225f53Skettenis 			if ((HREAD4(sc, SDMMC_CTRL) &
450*24225f53Skettenis 			    SDMMC_CTRL_FIFO_RESET) == 0)
451*24225f53Skettenis 				break;
452*24225f53Skettenis 			delay(100);
453*24225f53Skettenis 		}
454*24225f53Skettenis 		if (timeout == 0)
455*24225f53Skettenis 			printf("%s: FIFO reset failed\n", sc->sc_dev.dv_xname);
456*24225f53Skettenis 
457*24225f53Skettenis 		cmdval |= SDMMC_CMD_DATA_EXPECTED;
458*24225f53Skettenis 		if (!ISSET(cmd->c_flags, SCF_CMD_READ))
459*24225f53Skettenis 			cmdval |= SDMMC_CMD_WR;
460*24225f53Skettenis 	}
461*24225f53Skettenis 
462*24225f53Skettenis 	HWRITE4(sc, SDMMC_RINTSTS, 0xffffffff);
463*24225f53Skettenis 
464*24225f53Skettenis 	HWRITE4(sc, SDMMC_CMDARG, cmd->c_arg);
465*24225f53Skettenis 	HWRITE4(sc, SDMMC_CMD, cmdval | cmd->c_opcode);
466*24225f53Skettenis 
467*24225f53Skettenis 	for (timeout = 1000; timeout > 0; timeout--) {
468*24225f53Skettenis 		status = HREAD4(sc, SDMMC_RINTSTS);
469*24225f53Skettenis 		if (status & SDMMC_RINTSTS_CD)
470*24225f53Skettenis 			break;
471*24225f53Skettenis 		delay(100);
472*24225f53Skettenis 	}
473*24225f53Skettenis 	if (timeout == 0 || status & SDMMC_RINTSTS_RTO) {
474*24225f53Skettenis 		cmd->c_error = ETIMEDOUT;
475*24225f53Skettenis 		goto done;
476*24225f53Skettenis 	}
477*24225f53Skettenis 
478*24225f53Skettenis 	if (cmd->c_flags & SCF_RSP_PRESENT) {
479*24225f53Skettenis 		if (cmd->c_flags & SCF_RSP_136) {
480*24225f53Skettenis 			cmd->c_resp[0] = HREAD4(sc, SDMMC_RESP0);
481*24225f53Skettenis 			cmd->c_resp[1] = HREAD4(sc, SDMMC_RESP1);
482*24225f53Skettenis 			cmd->c_resp[2] = HREAD4(sc, SDMMC_RESP2);
483*24225f53Skettenis 			cmd->c_resp[3] = HREAD4(sc, SDMMC_RESP3);
484*24225f53Skettenis 			if (cmd->c_flags & SCF_RSP_CRC) {
485*24225f53Skettenis 				cmd->c_resp[0] = (cmd->c_resp[0] >> 8) |
486*24225f53Skettenis 				    (cmd->c_resp[1] << 24);
487*24225f53Skettenis 				cmd->c_resp[1] = (cmd->c_resp[1] >> 8) |
488*24225f53Skettenis 				    (cmd->c_resp[2] << 24);
489*24225f53Skettenis 				cmd->c_resp[2] = (cmd->c_resp[2] >> 8) |
490*24225f53Skettenis 				    (cmd->c_resp[3] << 24);
491*24225f53Skettenis 				cmd->c_resp[3] = (cmd->c_resp[3] >> 8);
492*24225f53Skettenis 			}
493*24225f53Skettenis 		} else {
494*24225f53Skettenis 			cmd->c_resp[0] = HREAD4(sc, SDMMC_RESP0);
495*24225f53Skettenis 		}
496*24225f53Skettenis 	}
497*24225f53Skettenis 
498*24225f53Skettenis 	if (cmd->c_datalen > 0)
499*24225f53Skettenis 		dwmmc_transfer_data(sc, cmd);
500*24225f53Skettenis 
501*24225f53Skettenis 	if (cmdval & SDMMC_CMD_SEND_AUTO_STOP) {
502*24225f53Skettenis 		for (timeout = 10000; timeout > 0; timeout--) {
503*24225f53Skettenis 			status = HREAD4(sc, SDMMC_RINTSTS);
504*24225f53Skettenis 			if (status & SDMMC_RINTSTS_CD)
505*24225f53Skettenis 				break;
506*24225f53Skettenis 			delay(10);
507*24225f53Skettenis 		}
508*24225f53Skettenis 		if (timeout == 0) {
509*24225f53Skettenis 			cmd->c_error = ETIMEDOUT;
510*24225f53Skettenis 			goto done;
511*24225f53Skettenis 		}
512*24225f53Skettenis 	}
513*24225f53Skettenis 
514*24225f53Skettenis done:
515*24225f53Skettenis 	cmd->c_flags |= SCF_ITSDONE;
516*24225f53Skettenis #if 0
517*24225f53Skettenis 	printf("%s: err %d rintsts 0x%x\n", sc->sc_dev.dv_xname, cmd->c_error,
518*24225f53Skettenis 	    HREAD4(sc, SDMMC_RINTSTS));
519*24225f53Skettenis #endif
520*24225f53Skettenis 	splx(s);
521*24225f53Skettenis }
522*24225f53Skettenis 
523*24225f53Skettenis void
524*24225f53Skettenis dwmmc_transfer_data(struct dwmmc_softc *sc, struct sdmmc_command *cmd)
525*24225f53Skettenis {
526*24225f53Skettenis 	int datalen = cmd->c_datalen;
527*24225f53Skettenis 	u_char *datap = cmd->c_data;
528*24225f53Skettenis 	uint32_t status;
529*24225f53Skettenis 	int count, timeout;
530*24225f53Skettenis 	int fifodr = SDMMC_RINTSTS_DTO;
531*24225f53Skettenis 
532*24225f53Skettenis 	if (ISSET(cmd->c_flags, SCF_CMD_READ))
533*24225f53Skettenis 		fifodr |= SDMMC_RINTSTS_RXDR;
534*24225f53Skettenis 	else
535*24225f53Skettenis 		fifodr |= SDMMC_RINTSTS_TXDR;
536*24225f53Skettenis 
537*24225f53Skettenis 	while (datalen > 0) {
538*24225f53Skettenis 		status = HREAD4(sc, SDMMC_RINTSTS);
539*24225f53Skettenis 		if (status & SDMMC_RINTSTS_DATA_ERR) {
540*24225f53Skettenis 			cmd->c_error = EIO;
541*24225f53Skettenis 			return;
542*24225f53Skettenis 		}
543*24225f53Skettenis 		if (status & SDMMC_RINTSTS_DATA_TO) {
544*24225f53Skettenis 			cmd->c_error = ETIMEDOUT;
545*24225f53Skettenis 			return;
546*24225f53Skettenis 		}
547*24225f53Skettenis 
548*24225f53Skettenis 		for (timeout = 10000; timeout > 0; timeout--) {
549*24225f53Skettenis 			status = HREAD4(sc, SDMMC_RINTSTS);
550*24225f53Skettenis 			if (status & fifodr)
551*24225f53Skettenis 				break;
552*24225f53Skettenis 			delay(100);
553*24225f53Skettenis 		}
554*24225f53Skettenis 		if (timeout == 0) {
555*24225f53Skettenis 			cmd->c_error = ETIMEDOUT;
556*24225f53Skettenis 			return;
557*24225f53Skettenis 		}
558*24225f53Skettenis 
559*24225f53Skettenis 		count = SDMMC_STATUS_FIFO_COUNT(HREAD4(sc, SDMMC_STATUS));
560*24225f53Skettenis 		if (!ISSET(cmd->c_flags, SCF_CMD_READ))
561*24225f53Skettenis 		    count = sc->sc_fifo_depth - count;
562*24225f53Skettenis 
563*24225f53Skettenis 		count = MIN(datalen, count * 4);
564*24225f53Skettenis 		if (ISSET(cmd->c_flags, SCF_CMD_READ))
565*24225f53Skettenis 			dwmmc_read_data(sc, datap, count);
566*24225f53Skettenis 		else
567*24225f53Skettenis 			dwmmc_write_data(sc, datap, count);
568*24225f53Skettenis 
569*24225f53Skettenis 		datap += count;
570*24225f53Skettenis 		datalen -= count;
571*24225f53Skettenis 	}
572*24225f53Skettenis 
573*24225f53Skettenis 	for (timeout = 1000; timeout > 0; timeout--) {
574*24225f53Skettenis 		status = HREAD4(sc, SDMMC_RINTSTS);
575*24225f53Skettenis 		if (status & SDMMC_RINTSTS_DTO)
576*24225f53Skettenis 			break;
577*24225f53Skettenis 		delay(100);
578*24225f53Skettenis 	}
579*24225f53Skettenis 	if (timeout == 0)
580*24225f53Skettenis 		cmd->c_error = ETIMEDOUT;
581*24225f53Skettenis }
582*24225f53Skettenis 
583*24225f53Skettenis void
584*24225f53Skettenis dwmmc_read_data(struct dwmmc_softc *sc, u_char *datap, int datalen)
585*24225f53Skettenis {
586*24225f53Skettenis 	while (datalen > 3) {
587*24225f53Skettenis 		*(uint32_t *)datap = HREAD4(sc, SDMMC_FIFO_BASE);
588*24225f53Skettenis 		datap += 4;
589*24225f53Skettenis 		datalen -= 4;
590*24225f53Skettenis 	}
591*24225f53Skettenis 	if (datalen > 0) {
592*24225f53Skettenis 		uint32_t rv = HREAD4(sc, SDMMC_FIFO_BASE);
593*24225f53Skettenis 		do {
594*24225f53Skettenis 			*datap++ = rv & 0xff;
595*24225f53Skettenis 			rv = rv >> 8;
596*24225f53Skettenis 		} while (--datalen > 0);
597*24225f53Skettenis 	}
598*24225f53Skettenis 	HWRITE4(sc, SDMMC_RINTSTS, SDMMC_RINTSTS_RXDR);
599*24225f53Skettenis }
600*24225f53Skettenis 
601*24225f53Skettenis void
602*24225f53Skettenis dwmmc_write_data(struct dwmmc_softc *sc, u_char *datap, int datalen)
603*24225f53Skettenis {
604*24225f53Skettenis 	while (datalen > 3) {
605*24225f53Skettenis 		HWRITE4(sc, SDMMC_FIFO_BASE, *((uint32_t *)datap));
606*24225f53Skettenis 		datap += 4;
607*24225f53Skettenis 		datalen -= 4;
608*24225f53Skettenis 	}
609*24225f53Skettenis 	if (datalen > 0) {
610*24225f53Skettenis 		uint32_t rv = *datap++;
611*24225f53Skettenis 		if (datalen > 1)
612*24225f53Skettenis 			rv |= *datap++ << 8;
613*24225f53Skettenis 		if (datalen > 2)
614*24225f53Skettenis 			rv |= *datap++ << 16;
615*24225f53Skettenis 		HWRITE4(sc, SDMMC_FIFO_BASE, rv);
616*24225f53Skettenis 	}
617*24225f53Skettenis 	HWRITE4(sc, SDMMC_RINTSTS, SDMMC_RINTSTS_TXDR);
618*24225f53Skettenis }
619