xref: /openbsd-src/sys/arch/octeon/dev/octmmc.c (revision 5e113959efb41efaa11aa7bc20ddb6afa37107aa)
1*5e113959Sjsg /*	$OpenBSD: octmmc.c,v 1.15 2023/04/12 02:20:07 jsg Exp $	*/
2abbc1723Svisa 
3abbc1723Svisa /*
4d2409bbdSvisa  * Copyright (c) 2016, 2017 Visa Hankala
5abbc1723Svisa  *
6abbc1723Svisa  * Permission to use, copy, modify, and/or distribute this software for any
7abbc1723Svisa  * purpose with or without fee is hereby granted, provided that the above
8abbc1723Svisa  * copyright notice and this permission notice appear in all copies.
9abbc1723Svisa  *
10abbc1723Svisa  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11abbc1723Svisa  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12abbc1723Svisa  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13abbc1723Svisa  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14abbc1723Svisa  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15abbc1723Svisa  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16abbc1723Svisa  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17abbc1723Svisa  */
18abbc1723Svisa 
19abbc1723Svisa /* Driver for OCTEON MMC host controller. */
20abbc1723Svisa 
21abbc1723Svisa #include <sys/param.h>
22abbc1723Svisa #include <sys/systm.h>
23abbc1723Svisa #include <sys/device.h>
24abbc1723Svisa #include <sys/endian.h>
25abbc1723Svisa #include <sys/malloc.h>
2610ff95a8Svisa #include <sys/mutex.h>
27abbc1723Svisa #include <sys/rwlock.h>
28abbc1723Svisa #include <sys/kernel.h>
29abbc1723Svisa 
30abbc1723Svisa #include <dev/ofw/fdt.h>
31b2699f5fSvisa #include <dev/ofw/ofw_gpio.h>
32abbc1723Svisa #include <dev/ofw/openfirm.h>
33abbc1723Svisa #include <dev/sdmmc/sdmmcchip.h>
34abbc1723Svisa #include <dev/sdmmc/sdmmcvar.h>
35abbc1723Svisa #include <dev/sdmmc/sdmmc_ioreg.h>
36abbc1723Svisa 
37abbc1723Svisa #include <mips64/cache.h>
38abbc1723Svisa 
39abbc1723Svisa #include <machine/bus.h>
40abbc1723Svisa #include <machine/fdt.h>
41abbc1723Svisa #include <machine/octeonreg.h>
42abbc1723Svisa #include <machine/octeonvar.h>
43abbc1723Svisa #include <machine/octeon_model.h>
44abbc1723Svisa 
45abbc1723Svisa #include <octeon/dev/octmmcreg.h>
46abbc1723Svisa 
47abbc1723Svisa #define OCTMMC_BLOCK_SIZE		512
48abbc1723Svisa #define OCTMMC_CMD_TIMEOUT		5		/* in seconds */
49a3bc953aSvisa #define OCTMMC_MAX_DMASEG		MIN(MAXPHYS, (1u << 18))
50bdafcb28Svisa #define OCTMMC_MAX_NDMASEG_6130		1
51bdafcb28Svisa #define OCTMMC_MAX_NDMASEG_7890		16
52abbc1723Svisa #define OCTMMC_MAX_FREQ			52000		/* in kHz */
53abbc1723Svisa #define OCTMMC_MAX_BUSES		4
54bfb70cb6Svisa #define OCTMMC_MAX_INTRS		4
55abbc1723Svisa 
56d2409bbdSvisa #define DEF_STS_MASK			0xe4390080ul
57d2409bbdSvisa #define PIO_STS_MASK			0x00b00000ul
58d2409bbdSvisa 
59abbc1723Svisa #define MMC_RD_8(sc, reg) \
60abbc1723Svisa 	bus_space_read_8((sc)->sc_iot, (sc)->sc_mmc_ioh, (reg))
61abbc1723Svisa #define MMC_WR_8(sc, reg, val) \
62abbc1723Svisa 	bus_space_write_8((sc)->sc_iot, (sc)->sc_mmc_ioh, (reg), (val))
63abbc1723Svisa #define DMA_WR_8(sc, reg, val) \
64abbc1723Svisa 	bus_space_write_8((sc)->sc_iot, (sc)->sc_dma_ioh, (reg), (val))
65bdafcb28Svisa #define FIFO_WR_8(sc, reg, val) \
66bdafcb28Svisa 	bus_space_write_8((sc)->sc_iot, (sc)->sc_fifo_ioh, (reg), (val))
67abbc1723Svisa 
68abbc1723Svisa #define divround(n, d) (((n) + (d) / 2) / (d))
69abbc1723Svisa 
70abbc1723Svisa struct octmmc_softc;
71abbc1723Svisa 
72abbc1723Svisa struct octmmc_bus {
73abbc1723Svisa 	struct octmmc_softc	*bus_hc;
74abbc1723Svisa 	struct device		*bus_sdmmc;
75abbc1723Svisa 	uint32_t		 bus_id;
76abbc1723Svisa 	uint32_t		 bus_cmd_skew;
77abbc1723Svisa 	uint32_t		 bus_dat_skew;
78abbc1723Svisa 	uint32_t		 bus_max_freq;		/* in kHz */
79abbc1723Svisa 	uint64_t		 bus_switch;
80abbc1723Svisa 	uint64_t		 bus_rca;
81abbc1723Svisa 	uint64_t		 bus_wdog;
82b2699f5fSvisa 	uint32_t		 bus_cd_gpio[3];
83abbc1723Svisa };
84abbc1723Svisa 
85abbc1723Svisa struct octmmc_softc {
86abbc1723Svisa 	struct device		 sc_dev;
87abbc1723Svisa 	bus_space_tag_t		 sc_iot;
88abbc1723Svisa 	bus_space_handle_t	 sc_mmc_ioh;
89abbc1723Svisa 	bus_space_handle_t	 sc_dma_ioh;
90bdafcb28Svisa 	bus_space_handle_t	 sc_fifo_ioh;
91abbc1723Svisa 	bus_dma_tag_t		 sc_dmat;
92abbc1723Svisa 	bus_dmamap_t		 sc_dma_data;
93a3bc953aSvisa 	caddr_t			 sc_bounce_buf;
94a3bc953aSvisa 	bus_dma_segment_t	 sc_bounce_seg;
95bfb70cb6Svisa 	void			*sc_ihs[OCTMMC_MAX_INTRS];
96bfb70cb6Svisa 	int			 sc_nihs;
97abbc1723Svisa 
98abbc1723Svisa 	struct octmmc_bus	 sc_buses[OCTMMC_MAX_BUSES];
99abbc1723Svisa 	struct octmmc_bus	*sc_current_bus;
100abbc1723Svisa 
101abbc1723Svisa 	uint64_t		 sc_current_switch;
102abbc1723Svisa 	uint64_t		 sc_intr_status;
10310ff95a8Svisa 	struct mutex		 sc_intr_mtx;
104bfb70cb6Svisa 
105bfb70cb6Svisa 	int			 sc_hwrev;
106bfb70cb6Svisa #define OCTMMC_HWREV_6130			0
107bfb70cb6Svisa #define OCTMMC_HWREV_7890			1
108abbc1723Svisa };
109abbc1723Svisa 
110abbc1723Svisa int	 octmmc_match(struct device *, void *, void *);
111abbc1723Svisa void	 octmmc_attach(struct device *, struct device *, void *);
112abbc1723Svisa 
113abbc1723Svisa int	 octmmc_host_reset(sdmmc_chipset_handle_t);
114abbc1723Svisa uint32_t octmmc_host_ocr(sdmmc_chipset_handle_t);
115abbc1723Svisa int	 octmmc_host_maxblklen(sdmmc_chipset_handle_t);
116abbc1723Svisa int	 octmmc_card_detect(sdmmc_chipset_handle_t);
117abbc1723Svisa int	 octmmc_bus_width(sdmmc_chipset_handle_t, int);
118abbc1723Svisa int	 octmmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
119abbc1723Svisa int	 octmmc_bus_clock(sdmmc_chipset_handle_t, int, int);
120abbc1723Svisa void	 octmmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
121abbc1723Svisa 
122abbc1723Svisa void	 octmmc_exec_dma(struct octmmc_bus *, struct sdmmc_command *);
123abbc1723Svisa void	 octmmc_exec_pio(struct octmmc_bus *, struct sdmmc_command *);
124abbc1723Svisa 
125abbc1723Svisa void	 octmmc_acquire(struct octmmc_bus *);
126abbc1723Svisa void	 octmmc_release(struct octmmc_bus *);
127abbc1723Svisa 
128bdafcb28Svisa paddr_t	 octmmc_dma_load_6130(struct octmmc_softc *, struct sdmmc_command *);
129bdafcb28Svisa void	 octmmc_dma_load_7890(struct octmmc_softc *, struct sdmmc_command *);
130bdafcb28Svisa void	 octmmc_dma_unload_6130(struct octmmc_softc *, paddr_t);
131bdafcb28Svisa void	 octmmc_dma_unload_7890(struct octmmc_softc *);
132d2409bbdSvisa uint64_t octmmc_crtype_fixup(struct sdmmc_command *);
133abbc1723Svisa void	 octmmc_get_response(struct octmmc_softc *, struct sdmmc_command *);
134abbc1723Svisa int	 octmmc_init_bus(struct octmmc_bus *);
135abbc1723Svisa int	 octmmc_intr(void *);
136abbc1723Svisa int	 octmmc_wait_intr(struct octmmc_softc *, uint64_t, int);
137abbc1723Svisa 
138abbc1723Svisa const struct cfattach octmmc_ca = {
139abbc1723Svisa 	sizeof(struct octmmc_softc), octmmc_match, octmmc_attach
140abbc1723Svisa };
141abbc1723Svisa 
142abbc1723Svisa struct cfdriver octmmc_cd = {
143abbc1723Svisa 	NULL, "octmmc", DV_DULL
144abbc1723Svisa };
145abbc1723Svisa 
146abbc1723Svisa struct sdmmc_chip_functions octmmc_funcs = {
147abbc1723Svisa 	.host_reset	= octmmc_host_reset,
148abbc1723Svisa 	.host_ocr	= octmmc_host_ocr,
149abbc1723Svisa 	.host_maxblklen	= octmmc_host_maxblklen,
150abbc1723Svisa 	.card_detect	= octmmc_card_detect,
151abbc1723Svisa 	.bus_power	= octmmc_bus_power,
152abbc1723Svisa 	.bus_clock	= octmmc_bus_clock,
153abbc1723Svisa 	.bus_width	= octmmc_bus_width,
154abbc1723Svisa 	.exec_command	= octmmc_exec_command,
155abbc1723Svisa };
156abbc1723Svisa 
157bfb70cb6Svisa static const int octmmc_6130_interrupts[] = { 0, 1, -1 };
158bfb70cb6Svisa static const int octmmc_7890_interrupts[] = { 1, 2, 3, 4, -1 };
159bfb70cb6Svisa 
160abbc1723Svisa struct rwlock octmmc_lock = RWLOCK_INITIALIZER("octmmclk");
161abbc1723Svisa 
162abbc1723Svisa int
octmmc_match(struct device * parent,void * match,void * aux)163abbc1723Svisa octmmc_match(struct device *parent, void *match, void *aux)
164abbc1723Svisa {
165abbc1723Svisa 	struct fdt_attach_args *fa = aux;
166abbc1723Svisa 
167bfb70cb6Svisa 	return OF_is_compatible(fa->fa_node, "cavium,octeon-6130-mmc") ||
168bfb70cb6Svisa 	    OF_is_compatible(fa->fa_node, "cavium,octeon-7890-mmc");
169abbc1723Svisa }
170abbc1723Svisa 
171abbc1723Svisa void
octmmc_attach(struct device * parent,struct device * self,void * aux)172abbc1723Svisa octmmc_attach(struct device *parent, struct device *self, void *aux)
173abbc1723Svisa {
174abbc1723Svisa 	struct sdmmcbus_attach_args saa;
175abbc1723Svisa 	struct fdt_attach_args *fa = aux;
176abbc1723Svisa 	struct octmmc_softc *sc = (struct octmmc_softc *)self;
177abbc1723Svisa 	struct octmmc_bus *bus;
178bfb70cb6Svisa 	void *ih;
179bfb70cb6Svisa 	const int *interrupts;
180abbc1723Svisa 	uint64_t reg;
181abbc1723Svisa 	uint32_t bus_id, bus_width;
182bdafcb28Svisa 	int i, node;
183bdafcb28Svisa 	int maxsegs, rsegs;
184bfb70cb6Svisa 
185bfb70cb6Svisa 	if (OF_is_compatible(fa->fa_node, "cavium,octeon-7890-mmc")) {
186bfb70cb6Svisa 		sc->sc_hwrev = OCTMMC_HWREV_7890;
187bfb70cb6Svisa 		interrupts = octmmc_7890_interrupts;
188bdafcb28Svisa 		maxsegs = OCTMMC_MAX_NDMASEG_7890;
189bfb70cb6Svisa 	} else {
190bfb70cb6Svisa 		sc->sc_hwrev = OCTMMC_HWREV_6130;
191bfb70cb6Svisa 		interrupts = octmmc_6130_interrupts;
192bdafcb28Svisa 		maxsegs = OCTMMC_MAX_NDMASEG_6130;
193bfb70cb6Svisa 	}
194abbc1723Svisa 
195abbc1723Svisa 	if (fa->fa_nreg < 2) {
196abbc1723Svisa 		printf(": expected 2 IO spaces, got %d\n", fa->fa_nreg);
197abbc1723Svisa 		return;
198abbc1723Svisa 	}
199abbc1723Svisa 
200abbc1723Svisa 	sc->sc_iot = fa->fa_iot;
201abbc1723Svisa 	sc->sc_dmat = fa->fa_dmat;
202abbc1723Svisa 	if (bus_space_map(sc->sc_iot, fa->fa_reg[0].addr, fa->fa_reg[0].size, 0,
203abbc1723Svisa 	    &sc->sc_mmc_ioh)) {
204abbc1723Svisa 		printf(": could not map MMC registers\n");
205abbc1723Svisa 		goto error;
206abbc1723Svisa 	}
207abbc1723Svisa 	if (bus_space_map(sc->sc_iot, fa->fa_reg[1].addr, fa->fa_reg[1].size, 0,
208abbc1723Svisa 	    &sc->sc_dma_ioh)) {
209abbc1723Svisa 		printf(": could not map DMA registers\n");
210abbc1723Svisa 		goto error;
211abbc1723Svisa 	}
212bdafcb28Svisa 	if (sc->sc_hwrev == OCTMMC_HWREV_7890 &&
213bdafcb28Svisa 	    bus_space_map(sc->sc_iot, fa->fa_reg[1].addr -
214bdafcb28Svisa 	      MIO_EMM_DMA_FIFO_REGSIZE, MIO_EMM_DMA_FIFO_REGSIZE, 0,
215bdafcb28Svisa 	    &sc->sc_fifo_ioh)) {
216bdafcb28Svisa 		printf(": could not map FIFO registers\n");
217bdafcb28Svisa 		goto error;
218bdafcb28Svisa 	}
219a3bc953aSvisa 	if (bus_dmamem_alloc(sc->sc_dmat, OCTMMC_MAX_DMASEG, 0, 0,
220a3bc953aSvisa 	    &sc->sc_bounce_seg, 1, &rsegs, BUS_DMA_NOWAIT)) {
221a3bc953aSvisa 		printf(": could not allocate bounce buffer\n");
222abbc1723Svisa 		goto error;
223abbc1723Svisa 	}
224a3bc953aSvisa 	if (bus_dmamem_map(sc->sc_dmat, &sc->sc_bounce_seg, rsegs,
225a3bc953aSvisa 	    OCTMMC_MAX_DMASEG, &sc->sc_bounce_buf,
226a3bc953aSvisa 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) {
227a3bc953aSvisa 		printf(": could not map bounce buffer\n");
228a3bc953aSvisa 		goto error_free;
229a3bc953aSvisa 	}
230bdafcb28Svisa 	if (bus_dmamap_create(sc->sc_dmat, OCTMMC_MAX_DMASEG, maxsegs,
231a3bc953aSvisa 	    OCTMMC_MAX_DMASEG, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
232a3bc953aSvisa 	    &sc->sc_dma_data)) {
233a3bc953aSvisa 		printf(": could not create data dmamap\n");
234a3bc953aSvisa 		goto error_unmap;
235a3bc953aSvisa 	}
236abbc1723Svisa 
237abbc1723Svisa 	/* Disable all buses. */
238abbc1723Svisa 	reg = MMC_RD_8(sc, MIO_EMM_CFG);
239abbc1723Svisa 	reg &= ~((1u << OCTMMC_MAX_BUSES) - 1);
240abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_CFG, reg);
241abbc1723Svisa 
242abbc1723Svisa 	/* Clear any pending interrupts. */
243abbc1723Svisa 	reg = MMC_RD_8(sc, MIO_EMM_INT);
244abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_INT, reg);
245abbc1723Svisa 
246bfb70cb6Svisa 	for (i = 0; interrupts[i] != -1; i++) {
247bfb70cb6Svisa 		KASSERT(i < OCTMMC_MAX_INTRS);
248bfb70cb6Svisa 		ih = octeon_intr_establish_fdt_idx(fa->fa_node, interrupts[i],
24910ff95a8Svisa 		    IPL_SDMMC | IPL_MPSAFE, octmmc_intr, sc, DEVNAME(sc));
250bfb70cb6Svisa 		if (ih == NULL) {
251bfb70cb6Svisa 			printf(": could not establish interrupt %d\n", i);
252a3bc953aSvisa 			goto error_intr;
253bfb70cb6Svisa 		}
254bfb70cb6Svisa 		sc->sc_ihs[i] = ih;
255bfb70cb6Svisa 		sc->sc_nihs++;
256bfb70cb6Svisa 	}
257abbc1723Svisa 
258abbc1723Svisa 	printf("\n");
259abbc1723Svisa 
260abbc1723Svisa 	sc->sc_current_bus = NULL;
261abbc1723Svisa 	sc->sc_current_switch = ~0ull;
262abbc1723Svisa 
26310ff95a8Svisa 	mtx_init(&sc->sc_intr_mtx, IPL_SDMMC);
26410ff95a8Svisa 
265abbc1723Svisa 	for (node = OF_child(fa->fa_node); node != 0; node = OF_peer(node)) {
266abbc1723Svisa 		if (!OF_is_compatible(node, "cavium,octeon-6130-mmc-slot"))
267abbc1723Svisa 			continue;
268abbc1723Svisa 		bus_id = OF_getpropint(node, "reg", (uint32_t)-1);
269abbc1723Svisa 		if (bus_id >= OCTMMC_MAX_BUSES)
270abbc1723Svisa 			continue;
271abbc1723Svisa 
272abbc1723Svisa 		bus = &sc->sc_buses[bus_id];
273abbc1723Svisa 		bus->bus_hc = sc;
274abbc1723Svisa 		bus->bus_id = bus_id;
275abbc1723Svisa 		bus->bus_cmd_skew = OF_getpropint(node,
276abbc1723Svisa 		    "cavium,cmd-clk-skew", 0);
277abbc1723Svisa 		bus->bus_dat_skew = OF_getpropint(node,
278abbc1723Svisa 		    "cavium,dat-clk-skew", 0);
279abbc1723Svisa 
280abbc1723Svisa 		bus->bus_max_freq = OF_getpropint(node,
281abbc1723Svisa 		    "spi-max-frequency", 0) / 1000;
282abbc1723Svisa 		if (bus->bus_max_freq == 0 ||
283abbc1723Svisa 		    bus->bus_max_freq > OCTMMC_MAX_FREQ)
284abbc1723Svisa 			bus->bus_max_freq = OCTMMC_MAX_FREQ;
285abbc1723Svisa 
286abbc1723Svisa 		bus_width = OF_getpropint(node, "bus-width", 0);
287abbc1723Svisa 		if (bus_width == 0)
288abbc1723Svisa 			bus_width = OF_getpropint(node,
289abbc1723Svisa 			    "cavium,bus-max-width", 8);
290abbc1723Svisa 
291b2699f5fSvisa 		OF_getpropintarray(node, "cd-gpios", bus->bus_cd_gpio,
292b2699f5fSvisa 		    sizeof(bus->bus_cd_gpio));
293b2699f5fSvisa 		if (bus->bus_cd_gpio[0] != 0)
294b2699f5fSvisa 			gpio_controller_config_pin(bus->bus_cd_gpio,
295b2699f5fSvisa 			    GPIO_CONFIG_INPUT);
296b2699f5fSvisa 
297abbc1723Svisa 		if (octmmc_init_bus(bus)) {
298abbc1723Svisa 			printf("%s: could not init bus %d\n", DEVNAME(sc),
299abbc1723Svisa 			    bus_id);
300abbc1723Svisa 			continue;
301abbc1723Svisa 		}
302abbc1723Svisa 
303abbc1723Svisa 		memset(&saa, 0, sizeof(saa));
304abbc1723Svisa 		saa.saa_busname = "sdmmc";
305abbc1723Svisa 		saa.sct = &octmmc_funcs;
306abbc1723Svisa 		saa.sch = bus;
307abbc1723Svisa 		saa.caps = SMC_CAPS_MMC_HIGHSPEED;
308abbc1723Svisa 		if (bus_width >= 8)
309abbc1723Svisa 			saa.caps |= SMC_CAPS_8BIT_MODE;
310abbc1723Svisa 		if (bus_width >= 4)
311abbc1723Svisa 			saa.caps |= SMC_CAPS_4BIT_MODE;
312abbc1723Svisa 
313abbc1723Svisa 		bus->bus_sdmmc = config_found(&sc->sc_dev, &saa, NULL);
314abbc1723Svisa 		if (bus->bus_sdmmc == NULL)
315abbc1723Svisa 			printf("%s: bus %d: could not attach sdmmc\n",
316abbc1723Svisa 			    DEVNAME(sc), bus_id);
317abbc1723Svisa 	}
318abbc1723Svisa 	return;
319abbc1723Svisa 
320a3bc953aSvisa error_intr:
321bfb70cb6Svisa 	for (i = 0; i < sc->sc_nihs; i++)
322bfb70cb6Svisa 		octeon_intr_disestablish_fdt(sc->sc_ihs[i]);
323a3bc953aSvisa error_unmap:
324a3bc953aSvisa 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_bounce_buf, OCTMMC_MAX_DMASEG);
325a3bc953aSvisa error_free:
326a3bc953aSvisa 	bus_dmamem_free(sc->sc_dmat, &sc->sc_bounce_seg, rsegs);
327a3bc953aSvisa error:
328abbc1723Svisa 	if (sc->sc_dma_data != NULL)
329abbc1723Svisa 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_dma_data);
330bdafcb28Svisa 	if (sc->sc_fifo_ioh != 0)
331bdafcb28Svisa 		bus_space_unmap(sc->sc_iot, sc->sc_fifo_ioh,
332bdafcb28Svisa 		    MIO_EMM_DMA_FIFO_REGSIZE);
333abbc1723Svisa 	if (sc->sc_dma_ioh != 0)
334abbc1723Svisa 		bus_space_unmap(sc->sc_iot, sc->sc_dma_ioh, fa->fa_reg[1].size);
335abbc1723Svisa 	if (sc->sc_mmc_ioh != 0)
336abbc1723Svisa 		bus_space_unmap(sc->sc_iot, sc->sc_mmc_ioh, fa->fa_reg[0].size);
337abbc1723Svisa }
338abbc1723Svisa 
339abbc1723Svisa void
octmmc_acquire(struct octmmc_bus * bus)340abbc1723Svisa octmmc_acquire(struct octmmc_bus *bus)
341abbc1723Svisa {
342abbc1723Svisa 	struct octmmc_softc *sc = bus->bus_hc;
343abbc1723Svisa 	uint64_t period, sample;
344abbc1723Svisa 
345abbc1723Svisa 	splassert(IPL_SDMMC);
346abbc1723Svisa 
347abbc1723Svisa 	rw_enter_write(&octmmc_lock);
348abbc1723Svisa 
349abbc1723Svisa 	/* Acquire the bootbus. */
350abbc1723Svisa 	octeon_xkphys_write_8(MIO_BOOT_CFG, 0);
351abbc1723Svisa 
352abbc1723Svisa 	if (sc->sc_current_bus == bus &&
353abbc1723Svisa 	    sc->sc_current_switch == bus->bus_switch)
354abbc1723Svisa 		return;
355abbc1723Svisa 
356abbc1723Svisa 	/* Save relative card address. */
357abbc1723Svisa 	if (sc->sc_current_bus != NULL)
358abbc1723Svisa 		sc->sc_current_bus->bus_rca = MMC_RD_8(sc, MIO_EMM_RCA);
359abbc1723Svisa 
360abbc1723Svisa 	sc->sc_current_bus = NULL;
361abbc1723Svisa 	sc->sc_current_switch = ~0ull;
362abbc1723Svisa 
363abbc1723Svisa 	/* Set bus parameters. */
364abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_SWITCH, bus->bus_switch &
365abbc1723Svisa 	    ~MIO_EMM_SWITCH_BUS_ID);
366abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_SWITCH, bus->bus_switch);
367abbc1723Svisa 
368abbc1723Svisa 	/* Set relative card address. */
369abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_RCA, bus->bus_rca);
370abbc1723Svisa 
371abbc1723Svisa 	/* Set command timeout. */
372abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_WDOG, bus->bus_wdog);
373abbc1723Svisa 
374abbc1723Svisa 	/* Set sampling skew parameters. */
375abbc1723Svisa 	period = 1000000000000ull / octeon_ioclock_speed();
376abbc1723Svisa 	sample = (divround(bus->bus_cmd_skew, period) <<
377abbc1723Svisa 	    MIO_EMM_SAMPLE_CMD_CNT_SHIFT) &
378abbc1723Svisa 	    MIO_EMM_SAMPLE_CMD_CNT;
379abbc1723Svisa 	sample |= (divround(bus->bus_dat_skew, period) <<
380abbc1723Svisa 	    MIO_EMM_SAMPLE_DAT_CNT_SHIFT) &
381abbc1723Svisa 	    MIO_EMM_SAMPLE_DAT_CNT;
382abbc1723Svisa 	MMC_WR_8(bus->bus_hc, MIO_EMM_SAMPLE, sample);
383abbc1723Svisa 
384abbc1723Svisa 	sc->sc_current_bus = bus;
385abbc1723Svisa 	sc->sc_current_switch = bus->bus_switch;
386abbc1723Svisa 	return;
387abbc1723Svisa }
388abbc1723Svisa 
389abbc1723Svisa void
octmmc_release(struct octmmc_bus * bus)390abbc1723Svisa octmmc_release(struct octmmc_bus *bus)
391abbc1723Svisa {
392abbc1723Svisa 	rw_exit_write(&octmmc_lock);
393abbc1723Svisa }
394abbc1723Svisa 
395abbc1723Svisa int
octmmc_init_bus(struct octmmc_bus * bus)396abbc1723Svisa octmmc_init_bus(struct octmmc_bus *bus)
397abbc1723Svisa {
398abbc1723Svisa 	struct octmmc_softc *sc = bus->bus_hc;
399abbc1723Svisa 	uint64_t init_freq = SDMMC_SDCLK_400KHZ;
400abbc1723Svisa 	uint64_t period;
401abbc1723Svisa 	uint64_t reg;
402abbc1723Svisa 	int s;
403abbc1723Svisa 
404abbc1723Svisa 	period = divround(octeon_ioclock_speed(), init_freq * 1000 * 2);
405abbc1723Svisa 	if (period > MIO_EMM_SWITCH_CLK_MAX)
406abbc1723Svisa 		period = MIO_EMM_SWITCH_CLK_MAX;
407abbc1723Svisa 
408abbc1723Svisa 	/* Set initial parameters. */
409abbc1723Svisa 	bus->bus_switch = (uint64_t)bus->bus_id << MIO_EMM_SWITCH_BUS_ID_SHIFT;
410abbc1723Svisa 	bus->bus_switch |= 10ull << MIO_EMM_SWITCH_POWER_CLASS_SHIFT;
411abbc1723Svisa 	bus->bus_switch |= period << MIO_EMM_SWITCH_CLK_HI_SHIFT;
412abbc1723Svisa 	bus->bus_switch |= period << MIO_EMM_SWITCH_CLK_LO_SHIFT;
413abbc1723Svisa 	bus->bus_rca = 1;
414abbc1723Svisa 
415abbc1723Svisa 	/* Make hardware timeout happen before timeout in software. */
416abbc1723Svisa 	bus->bus_wdog = init_freq * 900 * OCTMMC_CMD_TIMEOUT;
417abbc1723Svisa 	if (bus->bus_wdog > MIO_EMM_WDOG_CLK_CNT)
418abbc1723Svisa 		bus->bus_wdog = MIO_EMM_WDOG_CLK_CNT;
419abbc1723Svisa 
420abbc1723Svisa 	s = splsdmmc();
421abbc1723Svisa 
422abbc1723Svisa 	/* Enable the bus. */
423abbc1723Svisa 	reg = MMC_RD_8(sc, MIO_EMM_CFG);
424abbc1723Svisa 	reg |= 1u << bus->bus_id;
425abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_CFG, reg);
426abbc1723Svisa 
427abbc1723Svisa 	octmmc_acquire(bus);
428abbc1723Svisa 
429bfb70cb6Svisa 	/*
430bfb70cb6Svisa 	 * Enable interrupts.
431bfb70cb6Svisa 	 *
432bfb70cb6Svisa 	 * The mask register is present only on the revision 6130 controller
433bfb70cb6Svisa 	 * where interrupt causes share an interrupt vector.
434bfb70cb6Svisa 	 * The 7890 controller has a separate vector for each interrupt cause.
435bfb70cb6Svisa 	 */
436bfb70cb6Svisa 	if (sc->sc_hwrev == OCTMMC_HWREV_6130) {
437abbc1723Svisa 		MMC_WR_8(sc, MIO_EMM_INT_EN,
438abbc1723Svisa 		    MIO_EMM_INT_CMD_ERR | MIO_EMM_INT_CMD_DONE |
439abbc1723Svisa 		    MIO_EMM_INT_DMA_ERR | MIO_EMM_INT_DMA_DONE);
440bfb70cb6Svisa 	}
441abbc1723Svisa 
442d2409bbdSvisa 	MMC_WR_8(sc, MIO_EMM_STS_MASK, DEF_STS_MASK);
443abbc1723Svisa 
444abbc1723Svisa 	octmmc_release(bus);
445abbc1723Svisa 
446abbc1723Svisa 	splx(s);
447abbc1723Svisa 
448abbc1723Svisa 	return 0;
449abbc1723Svisa }
450abbc1723Svisa 
451abbc1723Svisa int
octmmc_intr(void * arg)452abbc1723Svisa octmmc_intr(void *arg)
453abbc1723Svisa {
454abbc1723Svisa 	struct octmmc_softc *sc = arg;
455abbc1723Svisa 	uint64_t isr;
456abbc1723Svisa 
457abbc1723Svisa 	/* Get and acknowledge pending interrupts. */
458abbc1723Svisa 	isr = MMC_RD_8(sc, MIO_EMM_INT);
459abbc1723Svisa 	if (isr == 0)
460abbc1723Svisa 		return 0;
461abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_INT, isr);
462abbc1723Svisa 
463abbc1723Svisa 	if (ISSET(isr, MIO_EMM_INT_CMD_DONE) ||
464abbc1723Svisa 	    ISSET(isr, MIO_EMM_INT_CMD_ERR) ||
465abbc1723Svisa 	    ISSET(isr, MIO_EMM_INT_DMA_DONE) ||
466abbc1723Svisa 	    ISSET(isr, MIO_EMM_INT_DMA_ERR)) {
46710ff95a8Svisa 		mtx_enter(&sc->sc_intr_mtx);
468abbc1723Svisa 		sc->sc_intr_status |= isr;
469abbc1723Svisa 		wakeup(&sc->sc_intr_status);
47010ff95a8Svisa 		mtx_leave(&sc->sc_intr_mtx);
471abbc1723Svisa 	}
472abbc1723Svisa 
473abbc1723Svisa 	return 1;
474abbc1723Svisa }
475abbc1723Svisa 
476abbc1723Svisa int
octmmc_host_reset(sdmmc_chipset_handle_t sch)477abbc1723Svisa octmmc_host_reset(sdmmc_chipset_handle_t sch)
478abbc1723Svisa {
479abbc1723Svisa 	struct octmmc_bus *bus = sch;
480abbc1723Svisa 	int s;
481abbc1723Svisa 
482abbc1723Svisa 	/* Force reswitch. */
483abbc1723Svisa 	bus->bus_hc->sc_current_switch = ~0ull;
484abbc1723Svisa 
485abbc1723Svisa 	s = splsdmmc();
486abbc1723Svisa 	octmmc_acquire(bus);
487abbc1723Svisa 	octmmc_release(bus);
488abbc1723Svisa 	splx(s);
489abbc1723Svisa 
490abbc1723Svisa 	return 0;
491abbc1723Svisa }
492abbc1723Svisa 
493abbc1723Svisa uint32_t
octmmc_host_ocr(sdmmc_chipset_handle_t sch)494abbc1723Svisa octmmc_host_ocr(sdmmc_chipset_handle_t sch)
495abbc1723Svisa {
496abbc1723Svisa 	/* The hardware does only 3.3V. */
497abbc1723Svisa 	return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V;
498abbc1723Svisa }
499abbc1723Svisa 
500abbc1723Svisa int
octmmc_host_maxblklen(sdmmc_chipset_handle_t sch)501abbc1723Svisa octmmc_host_maxblklen(sdmmc_chipset_handle_t sch)
502abbc1723Svisa {
503abbc1723Svisa 	return OCTMMC_BLOCK_SIZE;
504abbc1723Svisa }
505abbc1723Svisa 
506abbc1723Svisa int
octmmc_card_detect(sdmmc_chipset_handle_t sch)507abbc1723Svisa octmmc_card_detect(sdmmc_chipset_handle_t sch)
508abbc1723Svisa {
509b2699f5fSvisa 	struct octmmc_bus *bus = sch;
510b2699f5fSvisa 
511b2699f5fSvisa 	if (bus->bus_cd_gpio[0] != 0)
512b2699f5fSvisa 		return gpio_controller_get_pin(bus->bus_cd_gpio);
513b2699f5fSvisa 
514abbc1723Svisa 	return 1;
515abbc1723Svisa }
516abbc1723Svisa 
517abbc1723Svisa int
octmmc_bus_power(sdmmc_chipset_handle_t sch,uint32_t ocr)518abbc1723Svisa octmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
519abbc1723Svisa {
520abbc1723Svisa 	if (ocr == 0)
521abbc1723Svisa 		octmmc_host_reset(sch);
522abbc1723Svisa 
523abbc1723Svisa 	return 0;
524abbc1723Svisa }
525abbc1723Svisa 
526abbc1723Svisa int
octmmc_bus_clock(sdmmc_chipset_handle_t sch,int freq,int timing)527abbc1723Svisa octmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing)
528abbc1723Svisa {
529abbc1723Svisa 	struct octmmc_bus *bus = sch;
530abbc1723Svisa 	uint64_t ioclock = octeon_ioclock_speed();
531abbc1723Svisa 	uint64_t period;
532abbc1723Svisa 
533abbc1723Svisa 	if (freq == 0)
534abbc1723Svisa 		return 0;
535abbc1723Svisa 	if (freq > bus->bus_max_freq)
536abbc1723Svisa 		freq = bus->bus_max_freq;
537abbc1723Svisa 	period = divround(ioclock, freq * 1000 * 2);
538abbc1723Svisa 	if (period > MIO_EMM_SWITCH_CLK_MAX)
539abbc1723Svisa 		period = MIO_EMM_SWITCH_CLK_MAX;
540abbc1723Svisa 
541abbc1723Svisa 	bus->bus_switch &= ~MIO_EMM_SWITCH_CLK_HI;
542abbc1723Svisa 	bus->bus_switch &= ~MIO_EMM_SWITCH_CLK_LO;
543abbc1723Svisa 	bus->bus_switch |= period << MIO_EMM_SWITCH_CLK_HI_SHIFT;
544abbc1723Svisa 	bus->bus_switch |= period << MIO_EMM_SWITCH_CLK_LO_SHIFT;
545abbc1723Svisa 
546abbc1723Svisa 	/* Make hardware timeout happen before timeout in software. */
547abbc1723Svisa 	bus->bus_wdog = freq * 900 * OCTMMC_CMD_TIMEOUT;
548abbc1723Svisa 
549abbc1723Svisa 	if (timing)
550abbc1723Svisa 		bus->bus_switch |= MIO_EMM_SWITCH_HS_TIMING;
551abbc1723Svisa 	else
552abbc1723Svisa 		bus->bus_switch &= ~MIO_EMM_SWITCH_HS_TIMING;
553abbc1723Svisa 
554abbc1723Svisa 	return 0;
555abbc1723Svisa }
556abbc1723Svisa 
557abbc1723Svisa int
octmmc_bus_width(sdmmc_chipset_handle_t sch,int width)558abbc1723Svisa octmmc_bus_width(sdmmc_chipset_handle_t sch, int width)
559abbc1723Svisa {
560abbc1723Svisa 	struct octmmc_bus *bus = sch;
561abbc1723Svisa 	uint64_t bus_width;
562abbc1723Svisa 
563abbc1723Svisa 	switch (width) {
564abbc1723Svisa 	case 1:
565abbc1723Svisa 		bus_width = 0;
566abbc1723Svisa 		break;
567abbc1723Svisa 	case 4:
568abbc1723Svisa 		bus_width = 1;
569abbc1723Svisa 		break;
570abbc1723Svisa 	case 8:
571abbc1723Svisa 		bus_width = 2;
572abbc1723Svisa 		break;
573abbc1723Svisa 	default:
574abbc1723Svisa 		return ENOTSUP;
575abbc1723Svisa 	}
576abbc1723Svisa 	bus->bus_switch &= ~MIO_EMM_SWITCH_BUS_WIDTH;
577abbc1723Svisa 	bus->bus_switch |= bus_width << MIO_EMM_SWITCH_BUS_WIDTH_SHIFT;
578abbc1723Svisa 
579abbc1723Svisa 	return 0;
580abbc1723Svisa }
581abbc1723Svisa 
582abbc1723Svisa void
octmmc_exec_command(sdmmc_chipset_handle_t sch,struct sdmmc_command * cmd)583abbc1723Svisa octmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
584abbc1723Svisa {
585abbc1723Svisa 	struct octmmc_bus *bus = sch;
586abbc1723Svisa 
587abbc1723Svisa 	/*
5887aa7a19aSvisa 	 * Refuse SDIO probe. Proper SDIO operation is not possible
5897aa7a19aSvisa 	 * because of a lack of card interrupt handling.
5907aa7a19aSvisa 	 */
5917aa7a19aSvisa 	if (cmd->c_opcode == SD_IO_SEND_OP_COND) {
5927aa7a19aSvisa 		cmd->c_error = ENOTSUP;
5937aa7a19aSvisa 		return;
5947aa7a19aSvisa 	}
5957aa7a19aSvisa 
5967aa7a19aSvisa 	/*
597abbc1723Svisa 	 * The DMA mode can only do data block transfers. Other commands have
598abbc1723Svisa 	 * to use the PIO mode. Single-block transfers can use PIO because
599abbc1723Svisa 	 * it has low setup overhead.
600abbc1723Svisa 	 */
601abbc1723Svisa 	if (cmd->c_opcode == MMC_READ_BLOCK_MULTIPLE ||
602abbc1723Svisa 	    cmd->c_opcode == MMC_WRITE_BLOCK_MULTIPLE)
603abbc1723Svisa 		octmmc_exec_dma(bus, cmd);
604abbc1723Svisa 	else
605abbc1723Svisa 		octmmc_exec_pio(bus, cmd);
606abbc1723Svisa }
607abbc1723Svisa 
608abbc1723Svisa void
octmmc_exec_dma(struct octmmc_bus * bus,struct sdmmc_command * cmd)609abbc1723Svisa octmmc_exec_dma(struct octmmc_bus *bus, struct sdmmc_command *cmd)
610abbc1723Svisa {
611abbc1723Svisa 	struct octmmc_softc *sc = bus->bus_hc;
612bdafcb28Svisa 	uint64_t dmacmd, status;
613abbc1723Svisa 	paddr_t locked_block = 0;
6142d34693aSvisa 	int bounce = 0;
615a3bc953aSvisa 	int s;
616abbc1723Svisa 
617abbc1723Svisa 	if (cmd->c_datalen > OCTMMC_MAX_DMASEG) {
618abbc1723Svisa 		cmd->c_error = ENOMEM;
619abbc1723Svisa 		return;
620abbc1723Svisa 	}
621abbc1723Svisa 
6224adfe401Svisa 	s = splsdmmc();
6234adfe401Svisa 	octmmc_acquire(bus);
6244adfe401Svisa 
6252d34693aSvisa 	/*
6262d34693aSvisa 	 * Attempt to use the buffer directly for DMA. In case the region
6272d34693aSvisa 	 * is not physically contiguous, bounce the data.
6282d34693aSvisa 	 */
6292d34693aSvisa 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_dma_data, cmd->c_data,
6302d34693aSvisa 	    cmd->c_datalen, NULL, BUS_DMA_WAITOK)) {
631a3bc953aSvisa 		cmd->c_error = bus_dmamap_load(sc->sc_dmat, sc->sc_dma_data,
632a3bc953aSvisa 		    sc->sc_bounce_buf, cmd->c_datalen, NULL, BUS_DMA_WAITOK);
633abbc1723Svisa 		if (cmd->c_error != 0)
6344adfe401Svisa 			goto dma_out;
635abbc1723Svisa 
6362d34693aSvisa 		bounce = 1;
6372d34693aSvisa 		if (!ISSET(cmd->c_flags, SCF_CMD_READ))
6382d34693aSvisa 			memcpy(sc->sc_bounce_buf, cmd->c_data, cmd->c_datalen);
6392d34693aSvisa 	}
6402d34693aSvisa 
641abbc1723Svisa 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_data, 0, cmd->c_datalen,
6422d34693aSvisa 	    ISSET(cmd->c_flags, SCF_CMD_READ) ? BUS_DMASYNC_PREREAD :
643abbc1723Svisa 	    BUS_DMASYNC_PREWRITE);
644abbc1723Svisa 
645bdafcb28Svisa 	if (sc->sc_hwrev == OCTMMC_HWREV_7890)
646bdafcb28Svisa 		octmmc_dma_load_7890(sc, cmd);
647bdafcb28Svisa 	else
648bdafcb28Svisa 		locked_block = octmmc_dma_load_6130(sc, cmd);
649abbc1723Svisa 
650d2409bbdSvisa 	/* Set status mask. */
651d2409bbdSvisa 	MMC_WR_8(sc, MIO_EMM_STS_MASK, DEF_STS_MASK);
652d2409bbdSvisa 
65310ff95a8Svisa 	mtx_enter(&sc->sc_intr_mtx);
65410ff95a8Svisa 
655abbc1723Svisa 	/* Prepare and issue the command. */
656abbc1723Svisa 	dmacmd = MIO_EMM_DMA_DMA_VAL | MIO_EMM_DMA_MULTI | MIO_EMM_DMA_SECTOR;
657abbc1723Svisa 	dmacmd |= (uint64_t)bus->bus_id << MIO_EMM_DMA_BUS_ID_SHIFT;
658abbc1723Svisa 	dmacmd |= (uint64_t)(cmd->c_datalen / cmd->c_blklen) <<
659abbc1723Svisa 	    MIO_EMM_DMA_BLOCK_CNT_SHIFT;
660abbc1723Svisa 	dmacmd |= cmd->c_arg;
661abbc1723Svisa 	if (!ISSET(cmd->c_flags, SCF_CMD_READ))
662abbc1723Svisa 		dmacmd |= MIO_EMM_DMA_RW;
663abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_DMA, dmacmd);
664abbc1723Svisa 
665abbc1723Svisa wait_intr:
666abbc1723Svisa 	cmd->c_error = octmmc_wait_intr(sc, MIO_EMM_INT_CMD_ERR |
667e5cd504fSvisa 	    MIO_EMM_INT_DMA_DONE | MIO_EMM_INT_DMA_ERR, OCTMMC_CMD_TIMEOUT);
668abbc1723Svisa 
669abbc1723Svisa 	status = MMC_RD_8(sc, MIO_EMM_RSP_STS);
670abbc1723Svisa 
671abbc1723Svisa 	/* Check DMA engine error. */
672abbc1723Svisa 	if (ISSET(sc->sc_intr_status, MIO_EMM_INT_DMA_ERR)) {
673abbc1723Svisa 		printf("%s: dma error\n", bus->bus_sdmmc->dv_xname);
674abbc1723Svisa 
675abbc1723Svisa 		if (ISSET(status, MIO_EMM_RSP_STS_DMA_PEND)) {
676abbc1723Svisa 			/* Try to stop the DMA engine. */
677abbc1723Svisa 			dmacmd = MMC_RD_8(sc, MIO_EMM_DMA);
678abbc1723Svisa 			dmacmd |= MIO_EMM_DMA_DMA_VAL | MIO_EMM_DMA_DAT_NULL;
679abbc1723Svisa 			dmacmd &= ~MIO_EMM_DMA_BUS_ID;
680abbc1723Svisa 			dmacmd |= (uint64_t)bus->bus_id <<
681abbc1723Svisa 			    MIO_EMM_DMA_BUS_ID_SHIFT;
682abbc1723Svisa 			MMC_WR_8(sc, MIO_EMM_DMA, dmacmd);
683abbc1723Svisa 			goto wait_intr;
684abbc1723Svisa 		}
685abbc1723Svisa 		cmd->c_error = EIO;
686abbc1723Svisa 	}
68710ff95a8Svisa 
68810ff95a8Svisa 	mtx_leave(&sc->sc_intr_mtx);
68910ff95a8Svisa 
690abbc1723Svisa 	if (cmd->c_error != 0)
691abbc1723Svisa 		goto unload_dma;
692abbc1723Svisa 
693abbc1723Svisa 	/* Check command status. */
694abbc1723Svisa 	if (((status & MIO_EMM_RSP_STS_CMD_IDX) >>
695abbc1723Svisa 	    MIO_EMM_RSP_STS_CMD_IDX_SHIFT) != cmd->c_opcode ||
696abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_BLK_CRC_ERR) ||
697abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_DBUF_ERR) ||
698abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_RSP_BAD_STS) ||
699abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_RSP_CRC_ERR)) {
700abbc1723Svisa 		cmd->c_error = EIO;
701abbc1723Svisa 		goto unload_dma;
702abbc1723Svisa 	}
703abbc1723Svisa 	if (ISSET(status, MIO_EMM_RSP_STS_BLK_TIMEOUT) ||
704abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_RSP_TIMEOUT)) {
705abbc1723Svisa 		cmd->c_error = ETIMEDOUT;
706abbc1723Svisa 		goto unload_dma;
707abbc1723Svisa 	}
708abbc1723Svisa 
709abbc1723Svisa 	if (ISSET(cmd->c_flags, SCF_RSP_PRESENT))
710abbc1723Svisa 		octmmc_get_response(sc, cmd);
711abbc1723Svisa 
712abbc1723Svisa 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_data, 0, cmd->c_datalen,
7132d34693aSvisa 	    ISSET(cmd->c_flags, SCF_CMD_READ) ? BUS_DMASYNC_POSTREAD :
714abbc1723Svisa 	    BUS_DMASYNC_POSTWRITE);
7152d34693aSvisa 
7162d34693aSvisa 	if (bounce && ISSET(cmd->c_flags, SCF_CMD_READ))
7172d34693aSvisa 		memcpy(cmd->c_data, sc->sc_bounce_buf, cmd->c_datalen);
718abbc1723Svisa 
719abbc1723Svisa unload_dma:
720bdafcb28Svisa 	if (sc->sc_hwrev == OCTMMC_HWREV_7890)
721bdafcb28Svisa 		octmmc_dma_unload_7890(sc);
722bdafcb28Svisa 	else
723bdafcb28Svisa 		octmmc_dma_unload_6130(sc, locked_block);
724abbc1723Svisa 
7254adfe401Svisa 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_data);
7264adfe401Svisa 
7274adfe401Svisa dma_out:
728abbc1723Svisa 	octmmc_release(bus);
729abbc1723Svisa 	splx(s);
730abbc1723Svisa }
731abbc1723Svisa 
732abbc1723Svisa void
octmmc_exec_pio(struct octmmc_bus * bus,struct sdmmc_command * cmd)733abbc1723Svisa octmmc_exec_pio(struct octmmc_bus *bus, struct sdmmc_command *cmd)
734abbc1723Svisa {
735abbc1723Svisa 	struct octmmc_softc *sc = bus->bus_hc;
736abbc1723Svisa 	unsigned char *ptr;
737*5e113959Sjsg 	uint64_t piocmd, status, value;
738abbc1723Svisa 	unsigned int i;
739abbc1723Svisa 	int s;
740abbc1723Svisa 
741abbc1723Svisa 	if (cmd->c_datalen > OCTMMC_BLOCK_SIZE ||
742abbc1723Svisa 	    cmd->c_datalen % sizeof(uint64_t) != 0) {
743abbc1723Svisa 		cmd->c_error = EINVAL;
744abbc1723Svisa 		return;
745abbc1723Svisa 	}
746abbc1723Svisa 
747abbc1723Svisa 	s = splsdmmc();
748abbc1723Svisa 	octmmc_acquire(bus);
749abbc1723Svisa 
750abbc1723Svisa 	/* If this is a write, copy data to the controller's buffer. */
751abbc1723Svisa 	if (cmd->c_data != NULL && !ISSET(cmd->c_flags, SCF_CMD_READ)) {
752abbc1723Svisa 		/* Reset index and set autoincrement. */
753abbc1723Svisa 		MMC_WR_8(sc, MIO_EMM_BUF_IDX, MIO_EMM_BUF_IDX_INC);
754abbc1723Svisa 
755abbc1723Svisa 		ptr = cmd->c_data;
756abbc1723Svisa 		for (i = 0; i < cmd->c_datalen / sizeof(value); i++) {
757abbc1723Svisa 			memcpy(&value, ptr, sizeof(value));
758abbc1723Svisa 			MMC_WR_8(sc, MIO_EMM_BUF_DAT, value);
759abbc1723Svisa 			ptr += sizeof(value);
760abbc1723Svisa 		}
761abbc1723Svisa 	}
762abbc1723Svisa 
763d2409bbdSvisa 	/* Set status mask. */
764d2409bbdSvisa 	MMC_WR_8(sc, MIO_EMM_STS_MASK, PIO_STS_MASK);
765d2409bbdSvisa 
76610ff95a8Svisa 	mtx_enter(&sc->sc_intr_mtx);
76710ff95a8Svisa 
768abbc1723Svisa 	/* Issue the command. */
769abbc1723Svisa 	piocmd = MIO_EMM_CMD_CMD_VAL;
770abbc1723Svisa 	piocmd |= (uint64_t)bus->bus_id << MIO_EMM_CMD_BUS_ID_SHIFT;
771abbc1723Svisa 	piocmd |= (uint64_t)cmd->c_opcode << MIO_EMM_CMD_CMD_IDX_SHIFT;
772abbc1723Svisa 	piocmd |= cmd->c_arg;
773d2409bbdSvisa 	piocmd |= octmmc_crtype_fixup(cmd);
774abbc1723Svisa 	MMC_WR_8(sc, MIO_EMM_CMD, piocmd);
775abbc1723Svisa 
776abbc1723Svisa 	cmd->c_error = octmmc_wait_intr(sc, MIO_EMM_INT_CMD_DONE,
777e5cd504fSvisa 	    OCTMMC_CMD_TIMEOUT);
77810ff95a8Svisa 
77910ff95a8Svisa 	mtx_leave(&sc->sc_intr_mtx);
78010ff95a8Svisa 
781abbc1723Svisa 	if (cmd->c_error != 0)
782abbc1723Svisa 		goto pio_out;
783abbc1723Svisa 	if (ISSET(sc->sc_intr_status, MIO_EMM_INT_CMD_ERR)) {
784abbc1723Svisa 		cmd->c_error = EIO;
785abbc1723Svisa 		goto pio_out;
786abbc1723Svisa 	}
787abbc1723Svisa 
788abbc1723Svisa 	/* Check command status. */
789abbc1723Svisa 	status = MMC_RD_8(sc, MIO_EMM_RSP_STS);
790abbc1723Svisa 	if (((status & MIO_EMM_RSP_STS_CMD_IDX) >>
791abbc1723Svisa 	    MIO_EMM_RSP_STS_CMD_IDX_SHIFT) != cmd->c_opcode ||
792abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_BLK_CRC_ERR) ||
793abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_DBUF_ERR) ||
794abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_RSP_BAD_STS) ||
795abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_RSP_CRC_ERR)) {
796abbc1723Svisa 		cmd->c_error = EIO;
797abbc1723Svisa 		goto pio_out;
798abbc1723Svisa 	}
799abbc1723Svisa 	if (ISSET(status, MIO_EMM_RSP_STS_BLK_TIMEOUT) ||
800abbc1723Svisa 	    ISSET(status, MIO_EMM_RSP_STS_RSP_TIMEOUT)) {
801abbc1723Svisa 		cmd->c_error = ETIMEDOUT;
802abbc1723Svisa 		goto pio_out;
803abbc1723Svisa 	}
804abbc1723Svisa 
805abbc1723Svisa 	if (ISSET(cmd->c_flags, SCF_RSP_PRESENT))
806abbc1723Svisa 		octmmc_get_response(sc, cmd);
807abbc1723Svisa 
808abbc1723Svisa 	/* If this is a read, copy data from the controller's buffer. */
809abbc1723Svisa 	if (cmd->c_data != NULL && ISSET(cmd->c_flags, SCF_CMD_READ)) {
810*5e113959Sjsg 		/* Reset index and set autoincrement. */
811abbc1723Svisa 		MMC_WR_8(sc, MIO_EMM_BUF_IDX, MIO_EMM_BUF_IDX_INC);
812abbc1723Svisa 
813abbc1723Svisa 		ptr = cmd->c_data;
814abbc1723Svisa 		for (i = 0; i < cmd->c_datalen / sizeof(value); i++) {
815abbc1723Svisa 			value = MMC_RD_8(sc, MIO_EMM_BUF_DAT);
816abbc1723Svisa 			memcpy(ptr, &value, sizeof(value));
817abbc1723Svisa 			ptr += sizeof(value);
818abbc1723Svisa 		}
819abbc1723Svisa 	}
820abbc1723Svisa 
821abbc1723Svisa pio_out:
822abbc1723Svisa 	octmmc_release(bus);
823abbc1723Svisa 	splx(s);
824abbc1723Svisa }
825abbc1723Svisa 
826bdafcb28Svisa paddr_t
octmmc_dma_load_6130(struct octmmc_softc * sc,struct sdmmc_command * cmd)827bdafcb28Svisa octmmc_dma_load_6130(struct octmmc_softc *sc, struct sdmmc_command *cmd)
828bdafcb28Svisa {
829bdafcb28Svisa 	uint64_t dmacfg;
830bdafcb28Svisa 	paddr_t locked_block = 0;
831bdafcb28Svisa 
832bdafcb28Svisa 	/*
8331ffbd945Svisa 	 * The DMA hardware has a silicon bug that can corrupt data
8341ffbd945Svisa 	 * (erratum EMMC-17978). As a workaround, Linux locks the second last
8351ffbd945Svisa 	 * block of a transfer into the L2 cache if the opcode is multi-block
8361ffbd945Svisa 	 * write and there are more than two data blocks to write.
8371ffbd945Svisa 	 * In Linux, it is not described under what circumstances
8381ffbd945Svisa 	 * the corruption can happen.
839bdafcb28Svisa 	 * Lacking better information, use the same workaround here.
840bdafcb28Svisa 	 */
841bdafcb28Svisa 	if (cmd->c_opcode == MMC_WRITE_BLOCK_MULTIPLE &&
842bdafcb28Svisa 	    cmd->c_datalen > OCTMMC_BLOCK_SIZE * 2) {
843bdafcb28Svisa 		locked_block = sc->sc_dma_data->dm_segs[0].ds_addr +
844bdafcb28Svisa 		    sc->sc_dma_data->dm_segs[0].ds_len - OCTMMC_BLOCK_SIZE * 2;
845bdafcb28Svisa 		Octeon_lock_secondary_cache(curcpu(), locked_block,
846bdafcb28Svisa 		    OCTMMC_BLOCK_SIZE);
847bdafcb28Svisa 	}
848bdafcb28Svisa 
849bdafcb28Svisa 	/* Set up the DMA engine. */
850bdafcb28Svisa 	dmacfg = MIO_NDF_DMA_CFG_EN;
851bdafcb28Svisa 	if (!ISSET(cmd->c_flags, SCF_CMD_READ))
852bdafcb28Svisa 		dmacfg |= MIO_NDF_DMA_CFG_RW;
853bdafcb28Svisa 	dmacfg |= (sc->sc_dma_data->dm_segs[0].ds_len / sizeof(uint64_t) - 1)
854bdafcb28Svisa 	    << MIO_NDF_DMA_CFG_SIZE_SHIFT;
855bdafcb28Svisa 	dmacfg |= sc->sc_dma_data->dm_segs[0].ds_addr;
856bdafcb28Svisa 	DMA_WR_8(sc, MIO_NDF_DMA_CFG, dmacfg);
857bdafcb28Svisa 
858bdafcb28Svisa 	return locked_block;
859bdafcb28Svisa }
860bdafcb28Svisa 
861bdafcb28Svisa void
octmmc_dma_unload_6130(struct octmmc_softc * sc,paddr_t locked_block)862bdafcb28Svisa octmmc_dma_unload_6130(struct octmmc_softc *sc, paddr_t locked_block)
863bdafcb28Svisa {
864bdafcb28Svisa 	if (locked_block != 0)
865bdafcb28Svisa 		Octeon_unlock_secondary_cache(curcpu(), locked_block,
866bdafcb28Svisa 		    OCTMMC_BLOCK_SIZE);
867bdafcb28Svisa }
868bdafcb28Svisa 
869bdafcb28Svisa void
octmmc_dma_load_7890(struct octmmc_softc * sc,struct sdmmc_command * cmd)870bdafcb28Svisa octmmc_dma_load_7890(struct octmmc_softc *sc, struct sdmmc_command *cmd)
871bdafcb28Svisa {
872bdafcb28Svisa 	bus_dma_segment_t *seg;
873bdafcb28Svisa 	uint64_t fifocmd;
874bdafcb28Svisa 	int i;
875bdafcb28Svisa 
876bdafcb28Svisa 	/* Enable the FIFO. */
877bdafcb28Svisa 	FIFO_WR_8(sc, MIO_EMM_DMA_FIFO_CFG, 0);
878bdafcb28Svisa 
879bdafcb28Svisa 	for (i = 0; i < sc->sc_dma_data->dm_nsegs; i++) {
880bdafcb28Svisa 		seg = &sc->sc_dma_data->dm_segs[i];
881bdafcb28Svisa 
882bdafcb28Svisa 		fifocmd = (seg->ds_len / sizeof(uint64_t) - 1) <<
883bdafcb28Svisa 		    MIO_EMM_DMA_FIFO_CMD_SIZE_SHIFT;
884bdafcb28Svisa 		if (!ISSET(cmd->c_flags, SCF_CMD_READ))
885bdafcb28Svisa 			fifocmd |= MIO_EMM_DMA_FIFO_CMD_RW;
886bdafcb28Svisa 		if (i < sc->sc_dma_data->dm_nsegs - 1)
887bdafcb28Svisa 			fifocmd |= MIO_EMM_DMA_FIFO_CMD_INTDIS;
888bdafcb28Svisa 
889bdafcb28Svisa 		/* Create a FIFO entry. */
890bdafcb28Svisa 		FIFO_WR_8(sc, MIO_EMM_DMA_FIFO_ADR, seg->ds_addr);
891bdafcb28Svisa 		FIFO_WR_8(sc, MIO_EMM_DMA_FIFO_CMD, fifocmd);
892bdafcb28Svisa 	}
893bdafcb28Svisa }
894bdafcb28Svisa 
895bdafcb28Svisa void
octmmc_dma_unload_7890(struct octmmc_softc * sc)896bdafcb28Svisa octmmc_dma_unload_7890(struct octmmc_softc *sc)
897bdafcb28Svisa {
898bdafcb28Svisa 	/* Disable the FIFO. */
899bdafcb28Svisa 	FIFO_WR_8(sc, MIO_EMM_DMA_FIFO_CFG, MIO_EMM_DMA_FIFO_CFG_CLR);
900bdafcb28Svisa }
901bdafcb28Svisa 
902d2409bbdSvisa /*
903d2409bbdSvisa  * The controller uses MMC command and response types by default.
904d2409bbdSvisa  * When the command and response types of an SD opcode differ from those
905d2409bbdSvisa  * of an overlapping MMC opcode, it is necessary to fix the types.
906d2409bbdSvisa  * Fixing is also needed with a non-overlapping SD opcode when the command
907d2409bbdSvisa  * is a data transfer (adtc) or if a response is expected.
908d2409bbdSvisa  */
909d2409bbdSvisa uint64_t
octmmc_crtype_fixup(struct sdmmc_command * cmd)910d2409bbdSvisa octmmc_crtype_fixup(struct sdmmc_command *cmd)
911d2409bbdSvisa {
912d2409bbdSvisa 	uint64_t cxor = 0;
913d2409bbdSvisa 	uint64_t rxor = 0;
914d2409bbdSvisa 
915d2409bbdSvisa 	switch (cmd->c_opcode) {
916d2409bbdSvisa 	case SD_IO_SEND_OP_COND:
917d2409bbdSvisa 		cxor = 0x00;
918d2409bbdSvisa 		rxor = 0x02;
919d2409bbdSvisa 		break;
920d2409bbdSvisa 	case SD_SEND_IF_COND:
921d2409bbdSvisa 		/* The opcode overlaps with MMC_SEND_EXT_CSD. */
922d2409bbdSvisa 		if (SCF_CMD(cmd->c_flags) == SCF_CMD_BCR) {
923d2409bbdSvisa 			cxor = 0x01;
924d2409bbdSvisa 			rxor = 0x00;
925d2409bbdSvisa 		}
926d2409bbdSvisa 		break;
927d2409bbdSvisa 	case SD_APP_OP_COND:
928d2409bbdSvisa 		cxor = 0x00;
929d2409bbdSvisa 		rxor = 0x03;
930d2409bbdSvisa 		break;
931d2409bbdSvisa 	case SD_IO_RW_DIRECT:
932d2409bbdSvisa 	case SD_IO_RW_EXTENDED:
933d2409bbdSvisa 		cxor = 0x00;
934d2409bbdSvisa 		rxor = 0x01;
935d2409bbdSvisa 		break;
936d2409bbdSvisa 	}
937d2409bbdSvisa 	return (cxor << MIO_EMM_CMD_CTYPE_XOR_SHIFT) |
938d2409bbdSvisa 	    (rxor << MIO_EMM_CMD_RTYPE_XOR_SHIFT);
939d2409bbdSvisa }
940d2409bbdSvisa 
941abbc1723Svisa void
octmmc_get_response(struct octmmc_softc * sc,struct sdmmc_command * cmd)942abbc1723Svisa octmmc_get_response(struct octmmc_softc *sc, struct sdmmc_command *cmd)
943abbc1723Svisa {
944abbc1723Svisa 	uint64_t hi, lo;
945abbc1723Svisa 
946abbc1723Svisa 	if (ISSET(cmd->c_flags, SCF_RSP_136)) {
947abbc1723Svisa 		hi = MMC_RD_8(sc, MIO_EMM_RSP_HI);
948abbc1723Svisa 		lo = MMC_RD_8(sc, MIO_EMM_RSP_LO);
949abbc1723Svisa 
950abbc1723Svisa 		/* Discard the checksum. */
951abbc1723Svisa 		lo = (lo >> 8) | (hi << 56);
952abbc1723Svisa 		hi >>= 8;
953abbc1723Svisa 
954abbc1723Svisa 		/* The stack expects long response in little endian order. */
955abbc1723Svisa 		cmd->c_resp[0] = htole32(lo & 0xffffffffu);
956abbc1723Svisa 		cmd->c_resp[1] = htole32(lo >> 32);
957abbc1723Svisa 		cmd->c_resp[2] = htole32(hi & 0xffffffffu);
958abbc1723Svisa 		cmd->c_resp[3] = htole32(hi >> 32);
959abbc1723Svisa 	} else {
960abbc1723Svisa 		cmd->c_resp[0] = MMC_RD_8(sc, MIO_EMM_RSP_LO) >> 8;
961abbc1723Svisa 	}
962abbc1723Svisa }
963abbc1723Svisa 
964abbc1723Svisa int
octmmc_wait_intr(struct octmmc_softc * sc,uint64_t mask,int secs)965d7ed0b3dScheloha octmmc_wait_intr(struct octmmc_softc *sc, uint64_t mask, int secs)
966abbc1723Svisa {
96710ff95a8Svisa 	MUTEX_ASSERT_LOCKED(&sc->sc_intr_mtx);
968abbc1723Svisa 
969abbc1723Svisa 	mask |= MIO_EMM_INT_CMD_ERR | MIO_EMM_INT_DMA_ERR;
970abbc1723Svisa 
971abbc1723Svisa 	sc->sc_intr_status = 0;
972abbc1723Svisa 	while ((sc->sc_intr_status & mask) == 0) {
973d7ed0b3dScheloha 		if (msleep_nsec(&sc->sc_intr_status, &sc->sc_intr_mtx, PWAIT,
974d7ed0b3dScheloha 		    "hcintr", SEC_TO_NSEC(secs)) == EWOULDBLOCK)
975abbc1723Svisa 			return ETIMEDOUT;
976abbc1723Svisa 	}
977abbc1723Svisa 	return 0;
978abbc1723Svisa }
979