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