1*28d09237Sjsg /* $OpenBSD: ommmc.c,v 1.41 2024/05/22 05:51:49 jsg Exp $ */
28eda2d14Spatrick
38eda2d14Spatrick /*
48eda2d14Spatrick * Copyright (c) 2009 Dale Rahn <drahn@openbsd.org>
58eda2d14Spatrick * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
68eda2d14Spatrick *
78eda2d14Spatrick * Permission to use, copy, modify, and distribute this software for any
88eda2d14Spatrick * purpose with or without fee is hereby granted, provided that the above
98eda2d14Spatrick * copyright notice and this permission notice appear in all copies.
108eda2d14Spatrick *
118eda2d14Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
128eda2d14Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
138eda2d14Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
148eda2d14Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
158eda2d14Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
168eda2d14Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
178eda2d14Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
188eda2d14Spatrick */
198eda2d14Spatrick
208eda2d14Spatrick /* Omap SD/MMC support derived from /sys/dev/sdmmc/sdhc.c */
218eda2d14Spatrick
228eda2d14Spatrick
238eda2d14Spatrick #include <sys/param.h>
248eda2d14Spatrick #include <sys/device.h>
258eda2d14Spatrick #include <sys/systm.h>
268eda2d14Spatrick #include <machine/bus.h>
27d6b0164cSjsg #include <machine/fdt.h>
288eda2d14Spatrick
298eda2d14Spatrick #include <dev/sdmmc/sdmmcchip.h>
308eda2d14Spatrick #include <dev/sdmmc/sdmmcvar.h>
318eda2d14Spatrick
328eda2d14Spatrick #include <armv7/omap/prcmvar.h>
338eda2d14Spatrick
34d6b0164cSjsg #include <dev/ofw/openfirm.h>
351700f686Skettenis #include <dev/ofw/ofw_gpio.h>
3616f6b372Sjsg #include <dev/ofw/ofw_pinctrl.h>
37ac7c670eSpatrick #include <dev/ofw/fdt.h>
38d6b0164cSjsg
398eda2d14Spatrick /*
408eda2d14Spatrick * NOTE: on OMAP4430/AM335x these registers skew by 0x100
418eda2d14Spatrick * this is handled by mapping at base address + 0x100
428eda2d14Spatrick */
438eda2d14Spatrick /* registers */
448eda2d14Spatrick #define MMCHS_SYSCONFIG 0x010
458eda2d14Spatrick #define MMCHS_SYSSTATUS 0x014
468eda2d14Spatrick #define MMCHS_CSRE 0x024
478eda2d14Spatrick #define MMCHS_SYSTEST 0x028
48b746bbf9Sfgsch #define MMCHS_SYSTEST_SDCD (1 << 15)
498eda2d14Spatrick #define MMCHS_CON 0x02C
508eda2d14Spatrick #define MMCHS_CON_INIT (1<<1)
517d32c5c3Srapha #define MMCHS_CON_DW8 (1<<5)
527d32c5c3Srapha #define MMCHS_CON_OD (1<<0)
538eda2d14Spatrick #define MMCHS_PWCNT 0x030
548eda2d14Spatrick #define MMCHS_BLK 0x104
558eda2d14Spatrick #define MMCHS_BLK_NBLK_MAX 0xffff
568eda2d14Spatrick #define MMCHS_BLK_NBLK_SHIFT 16
578eda2d14Spatrick #define MMCHS_BLK_NBLK_MASK (MMCHS_BLK_NBLK_MAX<<MMCHS_BLK_NBLK_SHIFT)
588eda2d14Spatrick #define MMCHS_BLK_BLEN_MAX 0x400
598eda2d14Spatrick #define MMCHS_BLK_BLEN_SHIFT 0
608eda2d14Spatrick #define MMCHS_BLK_BLEN_MASK (MMCHS_BLK_BLEN_MAX<<MMCHS_BLK_BLEN_SHIFT)
618eda2d14Spatrick #define MMCHS_ARG 0x108
628eda2d14Spatrick #define MMCHS_CMD 0x10C
638eda2d14Spatrick #define MMCHS_CMD_INDX_SHIFT 24
648eda2d14Spatrick #define MMCHS_CMD_INDX_SHIFT_MASK (0x3f << MMCHS_CMD_INDX_SHIFT)
658eda2d14Spatrick #define MMCHS_CMD_CMD_TYPE_SHIFT 22
668eda2d14Spatrick #define MMCHS_CMD_DP_SHIFT 21
678eda2d14Spatrick #define MMCHS_CMD_DP (1 << MMCHS_CMD_DP_SHIFT)
688eda2d14Spatrick #define MMCHS_CMD_CICE_SHIFT 20
698eda2d14Spatrick #define MMCHS_CMD_CICE (1 << MMCHS_CMD_CICE_SHIFT)
708eda2d14Spatrick #define MMCHS_CMD_CCCE_SHIFT 19
718eda2d14Spatrick #define MMCHS_CMD_CCCE (1 << MMCHS_CMD_CCCE_SHIFT)
728eda2d14Spatrick #define MMCHS_CMD_RSP_TYPE_SHIFT 16
738eda2d14Spatrick #define MMCHS_CMD_RESP_NONE (0x0 << MMCHS_CMD_RSP_TYPE_SHIFT)
748eda2d14Spatrick #define MMCHS_CMD_RESP136 (0x1 << MMCHS_CMD_RSP_TYPE_SHIFT)
758eda2d14Spatrick #define MMCHS_CMD_RESP48 (0x2 << MMCHS_CMD_RSP_TYPE_SHIFT)
768eda2d14Spatrick #define MMCHS_CMD_RESP48B (0x3 << MMCHS_CMD_RSP_TYPE_SHIFT)
778eda2d14Spatrick #define MMCHS_CMD_MSBS (1 << 5)
788eda2d14Spatrick #define MMCHS_CMD_DDIR (1 << 4)
798eda2d14Spatrick #define MMCHS_CMD_ACEN (1 << 2)
808eda2d14Spatrick #define MMCHS_CMD_BCE (1 << 1)
818eda2d14Spatrick #define MMCHS_CMD_DE (1 << 0)
828eda2d14Spatrick #define MMCHS_RSP10 0x110
838eda2d14Spatrick #define MMCHS_RSP32 0x114
848eda2d14Spatrick #define MMCHS_RSP54 0x118
858eda2d14Spatrick #define MMCHS_RSP76 0x11C
868eda2d14Spatrick #define MMCHS_DATA 0x120
878eda2d14Spatrick #define MMCHS_PSTATE 0x124
888eda2d14Spatrick #define MMCHS_PSTATE_CLEV (1<<24)
898eda2d14Spatrick #define MMCHS_PSTATE_DLEV_SH 20
908eda2d14Spatrick #define MMCHS_PSTATE_DLEV_M (0xf << MMCHS_PSTATE_DLEV_SH)
918eda2d14Spatrick #define MMCHS_PSTATE_BRE (1<<11)
928eda2d14Spatrick #define MMCHS_PSTATE_BWE (1<<10)
938eda2d14Spatrick #define MMCHS_PSTATE_RTA (1<<9)
948eda2d14Spatrick #define MMCHS_PSTATE_WTA (1<<8)
958eda2d14Spatrick #define MMCHS_PSTATE_DLA (1<<2)
968eda2d14Spatrick #define MMCHS_PSTATE_DATI (1<<1)
978eda2d14Spatrick #define MMCHS_PSTATE_CMDI (1<<0)
988eda2d14Spatrick #define MMCHS_PSTATE_FMT "\20" \
998eda2d14Spatrick "\x098_CLEV" \
1008eda2d14Spatrick "\x08b_BRE" \
1018eda2d14Spatrick "\x08a_BWE" \
1028eda2d14Spatrick "\x089_RTA" \
1038eda2d14Spatrick "\x088_WTA" \
1048eda2d14Spatrick "\x082_DLA" \
1058eda2d14Spatrick "\x081_DATI" \
1068eda2d14Spatrick "\x080_CMDI"
1078eda2d14Spatrick #define MMCHS_HCTL 0x128
1088eda2d14Spatrick #define MMCHS_HCTL_SDVS_SHIFT 9
1098eda2d14Spatrick #define MMCHS_HCTL_SDVS_MASK (0x7<<MMCHS_HCTL_SDVS_SHIFT)
1108eda2d14Spatrick #define MMCHS_HCTL_SDVS_V18 (0x5<<MMCHS_HCTL_SDVS_SHIFT)
1118eda2d14Spatrick #define MMCHS_HCTL_SDVS_V30 (0x6<<MMCHS_HCTL_SDVS_SHIFT)
1128eda2d14Spatrick #define MMCHS_HCTL_SDVS_V33 (0x7<<MMCHS_HCTL_SDVS_SHIFT)
1138eda2d14Spatrick #define MMCHS_HCTL_SDBP (1<<8)
1147d32c5c3Srapha #define MMCHS_HCTL_HSPE (1<<2)
1158eda2d14Spatrick #define MMCHS_HCTL_DTW (1<<1)
1168eda2d14Spatrick #define MMCHS_SYSCTL 0x12C
1178eda2d14Spatrick #define MMCHS_SYSCTL_SRD (1<<26)
1188eda2d14Spatrick #define MMCHS_SYSCTL_SRC (1<<25)
1198eda2d14Spatrick #define MMCHS_SYSCTL_SRA (1<<24)
1208eda2d14Spatrick #define MMCHS_SYSCTL_DTO_SH 16
1218eda2d14Spatrick #define MMCHS_SYSCTL_DTO_MASK 0x000f0000
1228eda2d14Spatrick #define MMCHS_SYSCTL_CLKD_SH 6
1238eda2d14Spatrick #define MMCHS_SYSCTL_CLKD_MASK 0x0000ffc0
1248eda2d14Spatrick #define MMCHS_SYSCTL_CEN (1<<2)
1258eda2d14Spatrick #define MMCHS_SYSCTL_ICS (1<<1)
1268eda2d14Spatrick #define MMCHS_SYSCTL_ICE (1<<0)
1278eda2d14Spatrick #define MMCHS_STAT 0x130
1288eda2d14Spatrick #define MMCHS_STAT_BADA (1<<29)
1298eda2d14Spatrick #define MMCHS_STAT_CERR (1<<28)
1308eda2d14Spatrick #define MMCHS_STAT_ACE (1<<24)
1318eda2d14Spatrick #define MMCHS_STAT_DEB (1<<22)
1328eda2d14Spatrick #define MMCHS_STAT_DCRC (1<<21)
1338eda2d14Spatrick #define MMCHS_STAT_DTO (1<<20)
1348eda2d14Spatrick #define MMCHS_STAT_CIE (1<<19)
1358eda2d14Spatrick #define MMCHS_STAT_CEB (1<<18)
1368eda2d14Spatrick #define MMCHS_STAT_CCRC (1<<17)
1378eda2d14Spatrick #define MMCHS_STAT_CTO (1<<16)
1388eda2d14Spatrick #define MMCHS_STAT_ERRI (1<<15)
1398eda2d14Spatrick #define MMCHS_STAT_OBI (1<<9)
1408eda2d14Spatrick #define MMCHS_STAT_CIRQ (1<<8)
1418eda2d14Spatrick #define MMCHS_STAT_BRR (1<<5)
1428eda2d14Spatrick #define MMCHS_STAT_BWR (1<<4)
1438eda2d14Spatrick #define MMCHS_STAT_BGE (1<<2)
1448eda2d14Spatrick #define MMCHS_STAT_TC (1<<1)
1458eda2d14Spatrick #define MMCHS_STAT_CC (1<<0)
1468eda2d14Spatrick #define MMCHS_STAT_FMT "\20" \
1478eda2d14Spatrick "\x09d_BADA" \
1488eda2d14Spatrick "\x09c_CERR" \
1498eda2d14Spatrick "\x098_ACE" \
1508eda2d14Spatrick "\x096_DEB" \
1518eda2d14Spatrick "\x095_DCRC" \
1528eda2d14Spatrick "\x094_DTO" \
1538eda2d14Spatrick "\x093_CIE" \
1548eda2d14Spatrick "\x092_CEB" \
1558eda2d14Spatrick "\x091_CCRC" \
1568eda2d14Spatrick "\x090_CTO" \
1578eda2d14Spatrick "\x08f_ERRI" \
1588eda2d14Spatrick "\x089_OBI" \
1598eda2d14Spatrick "\x088_CIRQ" \
1608eda2d14Spatrick "\x085_BRR" \
1618eda2d14Spatrick "\x084_BWR" \
1628eda2d14Spatrick "\x082_BGE" \
1638eda2d14Spatrick "\x081_TC" \
1648eda2d14Spatrick "\x080_CC"
1658eda2d14Spatrick #define MMCHS_IE 0x134
1668eda2d14Spatrick #define MMCHS_ISE 0x138
1678eda2d14Spatrick #define MMCHS_AC12 0x13C
1688eda2d14Spatrick #define MMCHS_CAPA 0x140
1698eda2d14Spatrick #define MMCHS_CAPA_VS18 (1 << 26)
1708eda2d14Spatrick #define MMCHS_CAPA_VS30 (1 << 25)
1718eda2d14Spatrick #define MMCHS_CAPA_VS33 (1 << 24)
1728eda2d14Spatrick #define MMCHS_CAPA_SRS (1 << 23)
1738eda2d14Spatrick #define MMCHS_CAPA_DS (1 << 22)
1748eda2d14Spatrick #define MMCHS_CAPA_HSS (1 << 21)
1758eda2d14Spatrick #define MMCHS_CAPA_MBL_SHIFT 16
1768eda2d14Spatrick #define MMCHS_CAPA_MBL_MASK (3 << MMCHS_CAPA_MBL_SHIFT)
1778eda2d14Spatrick #define MMCHS_CUR_CAPA 0x148
1788eda2d14Spatrick #define MMCHS_REV 0x1fc
1798eda2d14Spatrick
18014877212Smpi #define SDHC_COMMAND_TIMEOUT 1 /* sec */
18114877212Smpi #define SDHC_BUFFER_TIMEOUT 1 /* sec */
18214877212Smpi #define SDHC_TRANSFER_TIMEOUT 1 /* sec */
1838eda2d14Spatrick
184d6b0164cSjsg int ommmc_match(struct device *, void *, void *);
185d6b0164cSjsg void ommmc_attach(struct device *, struct device *, void *);
1868eda2d14Spatrick
1878eda2d14Spatrick struct ommmc_softc {
1888eda2d14Spatrick struct device sc_dev;
1898eda2d14Spatrick bus_space_tag_t sc_iot;
1908eda2d14Spatrick bus_space_handle_t sc_ioh;
1911700f686Skettenis int sc_node;
1928eda2d14Spatrick void *sc_ih; /* Interrupt handler */
1931d4cb177Ssyl uint32_t sc_flags;
194ba989ecdSjsg #define FL_HSS (1 << 0)
1951700f686Skettenis uint32_t sc_gpio[4];
1968eda2d14Spatrick
1978eda2d14Spatrick struct device *sdmmc; /* generic SD/MMC device */
1988eda2d14Spatrick int clockbit; /* clock control bit */
1992252d02cSkettenis uint32_t clkbase; /* base clock frequency in kHz */
2008eda2d14Spatrick int maxblklen; /* maximum block length */
2018eda2d14Spatrick int flags; /* flags for this host */
2028eda2d14Spatrick uint32_t ocr; /* OCR value from capabilities */
2038eda2d14Spatrick uint32_t intr_status; /* soft interrupt status */
2048eda2d14Spatrick uint32_t intr_error_status; /* */
2058eda2d14Spatrick };
2068eda2d14Spatrick
2078eda2d14Spatrick
2088eda2d14Spatrick /* Host controller functions called by the attachment driver. */
2098eda2d14Spatrick void ommmc_power(int, void *);
2108eda2d14Spatrick void ommmc_shutdown(void *);
2118eda2d14Spatrick int ommmc_intr(void *);
2128eda2d14Spatrick
2138eda2d14Spatrick /* RESET MODES */
2148eda2d14Spatrick #define MMC_RESET_DAT 1
2158eda2d14Spatrick #define MMC_RESET_CMD 2
2168eda2d14Spatrick #define MMC_RESET_ALL (MMC_RESET_CMD|MMC_RESET_DAT)
2178eda2d14Spatrick
2188eda2d14Spatrick /* flag values */
2198eda2d14Spatrick #define SHF_USE_DMA 0x0001
2208eda2d14Spatrick
2218eda2d14Spatrick #define HREAD4(sc, reg) \
2228eda2d14Spatrick (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
2238eda2d14Spatrick #define HWRITE4(sc, reg, val) \
2248eda2d14Spatrick bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
2258eda2d14Spatrick #define HSET4(sc, reg, bits) \
2268eda2d14Spatrick HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
2278eda2d14Spatrick #define HCLR4(sc, reg, bits) \
2288eda2d14Spatrick HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
2298eda2d14Spatrick
2308eda2d14Spatrick int ommmc_host_reset(sdmmc_chipset_handle_t);
2318eda2d14Spatrick uint32_t ommmc_host_ocr(sdmmc_chipset_handle_t);
2328eda2d14Spatrick int ommmc_host_maxblklen(sdmmc_chipset_handle_t);
2338eda2d14Spatrick int ommmc_card_detect(sdmmc_chipset_handle_t);
2348eda2d14Spatrick int ommmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
235820e06f1Skettenis int ommmc_bus_clock(sdmmc_chipset_handle_t, int, int);
236e44746dcSjsg int ommmc_bus_width(sdmmc_chipset_handle_t, int);
2378eda2d14Spatrick void ommmc_card_intr_mask(sdmmc_chipset_handle_t, int);
2388eda2d14Spatrick void ommmc_card_intr_ack(sdmmc_chipset_handle_t);
2398eda2d14Spatrick void ommmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
2408eda2d14Spatrick int ommmc_start_command(struct ommmc_softc *, struct sdmmc_command *);
2418eda2d14Spatrick int ommmc_wait_state(struct ommmc_softc *, uint32_t, uint32_t);
2428eda2d14Spatrick int ommmc_soft_reset(struct ommmc_softc *, int);
2438eda2d14Spatrick int ommmc_wait_intr(struct ommmc_softc *, int, int);
2448eda2d14Spatrick void ommmc_transfer_data(struct ommmc_softc *, struct sdmmc_command *);
2451d4cb177Ssyl void ommmc_read_data(struct ommmc_softc *, uint8_t *, int);
2461d4cb177Ssyl void ommmc_write_data(struct ommmc_softc *, uint8_t *, int);
2478eda2d14Spatrick
2488eda2d14Spatrick /* #define SDHC_DEBUG */
2498eda2d14Spatrick #ifdef SDHC_DEBUG
2508eda2d14Spatrick int ommmcdebug = 20;
2518eda2d14Spatrick #define DPRINTF(n,s) do { if ((n) <= ommmcdebug) printf s; } while (0)
2528eda2d14Spatrick void ommmc_dump_regs(struct ommmc_softc *);
2538eda2d14Spatrick #else
2548eda2d14Spatrick #define DPRINTF(n,s) do {} while(0)
2558eda2d14Spatrick #endif
2568eda2d14Spatrick
2578eda2d14Spatrick struct sdmmc_chip_functions ommmc_functions = {
2588eda2d14Spatrick /* host controller reset */
2598eda2d14Spatrick ommmc_host_reset,
2608eda2d14Spatrick /* host controller capabilities */
2618eda2d14Spatrick ommmc_host_ocr,
2628eda2d14Spatrick ommmc_host_maxblklen,
2638eda2d14Spatrick /* card detection */
2648eda2d14Spatrick ommmc_card_detect,
2658eda2d14Spatrick /* bus power and clock frequency */
2668eda2d14Spatrick ommmc_bus_power,
2678eda2d14Spatrick ommmc_bus_clock,
268e44746dcSjsg ommmc_bus_width,
2698eda2d14Spatrick /* command execution */
2708eda2d14Spatrick ommmc_exec_command,
2718eda2d14Spatrick /* card interrupt */
2728eda2d14Spatrick ommmc_card_intr_mask,
2738eda2d14Spatrick ommmc_card_intr_ack
2748eda2d14Spatrick };
2758eda2d14Spatrick
2768eda2d14Spatrick struct cfdriver ommmc_cd = {
2778eda2d14Spatrick NULL, "ommmc", DV_DULL
2788eda2d14Spatrick };
2798eda2d14Spatrick
2809fdf0c62Smpi const struct cfattach ommmc_ca = {
281d6b0164cSjsg sizeof(struct ommmc_softc), ommmc_match, ommmc_attach
2828eda2d14Spatrick };
2838eda2d14Spatrick
284d6b0164cSjsg int
ommmc_match(struct device * parent,void * match,void * aux)285d6b0164cSjsg ommmc_match(struct device *parent, void *match, void *aux)
286d6b0164cSjsg {
287d6b0164cSjsg struct fdt_attach_args *faa = aux;
288d6b0164cSjsg
289d6b0164cSjsg return (OF_is_compatible(faa->fa_node, "ti,omap3-hsmmc") ||
2906b841390Sjsg OF_is_compatible(faa->fa_node, "ti,omap4-hsmmc") ||
2916b841390Sjsg OF_is_compatible(faa->fa_node, "ti,am335-sdhci"));
292d6b0164cSjsg }
293d6b0164cSjsg
2948eda2d14Spatrick void
ommmc_attach(struct device * parent,struct device * self,void * aux)295d6b0164cSjsg ommmc_attach(struct device *parent, struct device *self, void *aux)
2968eda2d14Spatrick {
2978eda2d14Spatrick struct ommmc_softc *sc = (struct ommmc_softc *) self;
298d6b0164cSjsg struct fdt_attach_args *faa = aux;
2998eda2d14Spatrick struct sdmmcbus_attach_args saa;
300ba989ecdSjsg uint32_t caps, width;
3017d7522cbSjsg uint32_t addr, size;
302d6b0164cSjsg int len, unit;
303d6b0164cSjsg char hwmods[128];
3048eda2d14Spatrick
3057d7522cbSjsg if (faa->fa_nreg < 1)
306d6b0164cSjsg return;
307d6b0164cSjsg
308ac7c670eSpatrick if (faa->fa_reg[0].size <= 0x100)
309d6b0164cSjsg return;
310d6b0164cSjsg
3116b841390Sjsg if (OF_is_compatible(faa->fa_node, "ti,omap4-hsmmc") ||
3126b841390Sjsg OF_is_compatible(faa->fa_node, "ti,am335-sdhci")) {
313ac7c670eSpatrick addr = faa->fa_reg[0].addr + 0x100;
314ac7c670eSpatrick size = faa->fa_reg[0].size - 0x100;
315d6b0164cSjsg } else {
316ac7c670eSpatrick addr = faa->fa_reg[0].addr;
317ac7c670eSpatrick size = faa->fa_reg[0].size;
318d6b0164cSjsg }
319d6b0164cSjsg
3204d149eb4Skettenis unit = -1;
321d6b0164cSjsg if ((len = OF_getprop(faa->fa_node, "ti,hwmods", hwmods,
322d6b0164cSjsg sizeof(hwmods))) == 5) {
323d6b0164cSjsg if (!strncmp(hwmods, "mmc", 3) &&
324d6b0164cSjsg (hwmods[3] > '0') && (hwmods[3] <= '9'))
325d6b0164cSjsg unit = hwmods[3] - '1';
326d6b0164cSjsg }
327d6b0164cSjsg
328d6b0164cSjsg sc->sc_iot = faa->fa_iot;
329d6b0164cSjsg if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh))
3308eda2d14Spatrick panic("%s: bus_space_map failed!", __func__);
3318eda2d14Spatrick
3321700f686Skettenis sc->sc_node = faa->fa_node;
3338eda2d14Spatrick printf("\n");
3348eda2d14Spatrick
33516f6b372Sjsg pinctrl_byname(faa->fa_node, "default");
3361558a2f3Sjsg
3374d9eaee2Ssyl /* Enable ICLKEN, FCLKEN? */
3384d149eb4Skettenis if (unit != -1)
339d6b0164cSjsg prcm_enablemodule(PRCM_MMC0 + unit);
3408eda2d14Spatrick
3417d7522cbSjsg sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_SDMMC,
3428c9b4ef8Ssyl ommmc_intr, sc, DEVNAME(sc));
3436ceec144Ssyl if (sc->sc_ih == NULL) {
3446ceec144Ssyl printf("%s: cannot map interrupt\n", DEVNAME(sc));
3456ceec144Ssyl goto err;
3466ceec144Ssyl }
3478eda2d14Spatrick
3481700f686Skettenis OF_getpropintarray(faa->fa_node, "cd-gpios", sc->sc_gpio,
3491700f686Skettenis sizeof(sc->sc_gpio));
3501700f686Skettenis if (sc->sc_gpio[0])
3511700f686Skettenis gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_INPUT);
3521700f686Skettenis
3538eda2d14Spatrick /* Controller Voltage Capabilities Initialization */
3548eda2d14Spatrick HSET4(sc, MMCHS_CAPA, MMCHS_CAPA_VS18 | MMCHS_CAPA_VS30);
3558eda2d14Spatrick
3568eda2d14Spatrick #ifdef SDHC_DEBUG
3578eda2d14Spatrick ommmc_dump_regs(sc);
3588eda2d14Spatrick #endif
3598eda2d14Spatrick
3608eda2d14Spatrick /*
3618eda2d14Spatrick * Reset the host controller and enable interrupts.
3628eda2d14Spatrick */
3636ceec144Ssyl ommmc_host_reset(sc);
3648eda2d14Spatrick
3658eda2d14Spatrick /* Determine host capabilities. */
3667d32c5c3Srapha caps = HREAD4(sc, MMCHS_CAPA);
3678eda2d14Spatrick
3687d32c5c3Srapha #if 0
3698eda2d14Spatrick /* we want this !! */
3708eda2d14Spatrick /* Use DMA if the host system and the controller support it. */
3718eda2d14Spatrick if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
3728eda2d14Spatrick SET(sc->flags, SHF_USE_DMA);
3738eda2d14Spatrick #endif
3748eda2d14Spatrick
3758eda2d14Spatrick /*
3768eda2d14Spatrick * Determine the base clock frequency. (2.2.24)
3778eda2d14Spatrick */
3788eda2d14Spatrick
3798eda2d14Spatrick sc->clkbase = 96 * 1000;
3808eda2d14Spatrick #if 0
3818eda2d14Spatrick if (SDHC_BASE_FREQ_KHZ(caps) != 0)
3828eda2d14Spatrick sc->clkbase = SDHC_BASE_FREQ_KHZ(caps);
3838eda2d14Spatrick #endif
3848eda2d14Spatrick if (sc->clkbase == 0) {
3858eda2d14Spatrick /* The attachment driver must tell us. */
3868c9b4ef8Ssyl printf("%s: base clock frequency unknown\n", DEVNAME(sc));
3878eda2d14Spatrick goto err;
3888eda2d14Spatrick } else if (sc->clkbase < 10000 || sc->clkbase > 96000) {
3898eda2d14Spatrick /* SDHC 1.0 supports only 10-63 MHz. */
3908eda2d14Spatrick printf("%s: base clock frequency out of range: %u MHz\n",
3918c9b4ef8Ssyl DEVNAME(sc), sc->clkbase / 1000);
3928eda2d14Spatrick goto err;
3938eda2d14Spatrick }
3948eda2d14Spatrick
3958eda2d14Spatrick /*
3968eda2d14Spatrick * XXX Set the data timeout counter value according to
3978eda2d14Spatrick * capabilities. (2.2.15)
3988eda2d14Spatrick */
3998eda2d14Spatrick
4008eda2d14Spatrick
4018eda2d14Spatrick /*
4028eda2d14Spatrick * Determine SD bus voltage levels supported by the controller.
4038eda2d14Spatrick */
4047d32c5c3Srapha if (caps & MMCHS_CAPA_VS18)
405b676d50fSkettenis SET(sc->ocr, MMC_OCR_1_65V_1_95V);
4067d32c5c3Srapha if (caps & MMCHS_CAPA_VS30)
4078eda2d14Spatrick SET(sc->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
4087d32c5c3Srapha if (caps & MMCHS_CAPA_VS33)
4098eda2d14Spatrick SET(sc->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
4108eda2d14Spatrick
4118eda2d14Spatrick /*
4128eda2d14Spatrick * Omap max block size is fixed (single buffer), could limit
4138eda2d14Spatrick * this to 512 for double buffering, but dont see the point.
4148eda2d14Spatrick */
4157d32c5c3Srapha switch ((caps & MMCHS_CAPA_MBL_MASK) >> MMCHS_CAPA_MBL_SHIFT) {
4168eda2d14Spatrick case 0:
4178eda2d14Spatrick sc->maxblklen = 512;
4188eda2d14Spatrick break;
4198eda2d14Spatrick case 1:
4208eda2d14Spatrick sc->maxblklen = 1024;
4218eda2d14Spatrick break;
4228eda2d14Spatrick case 2:
4238eda2d14Spatrick sc->maxblklen = 2048;
4248eda2d14Spatrick break;
4258eda2d14Spatrick default:
4268eda2d14Spatrick sc->maxblklen = 512;
4278eda2d14Spatrick printf("invalid capability blocksize in capa %08x,"
4288eda2d14Spatrick " trying 512\n", HREAD4(sc, MMCHS_CAPA));
4298eda2d14Spatrick }
4308eda2d14Spatrick /*
4315dd2055aSsyl * MMC does not support blksize > 512 yet
4325dd2055aSsyl */
4335dd2055aSsyl sc->maxblklen = 512;
4345dd2055aSsyl /*
4358eda2d14Spatrick * Attach the generic SD/MMC bus driver. (The bus driver must
4368eda2d14Spatrick * not invoke any chipset functions before it is attached.)
4378eda2d14Spatrick */
4388eda2d14Spatrick bzero(&saa, sizeof(saa));
4398eda2d14Spatrick saa.saa_busname = "sdmmc";
4408eda2d14Spatrick saa.sct = &ommmc_functions;
4418eda2d14Spatrick saa.sch = sc;
442ba989ecdSjsg if (OF_getproplen(faa->fa_node, "ti,needs-special-hs-handling") == 0 &&
443ba989ecdSjsg (caps & MMCHS_CAPA_HSS)) {
444ba989ecdSjsg sc->sc_flags |= FL_HSS;
445ba989ecdSjsg saa.caps |= SMC_CAPS_MMC_HIGHSPEED | SMC_CAPS_SD_HIGHSPEED;
446ba989ecdSjsg }
447ba989ecdSjsg width = OF_getpropint(faa->fa_node, "bus-width", 1);
448ba989ecdSjsg /* with bbb emmc width > 1 ommmc_wait_intr MMCHS_STAT_CC times out */
4494d149eb4Skettenis if (unit > 0)
450ba989ecdSjsg width = 1;
451ba989ecdSjsg if (width >= 8)
452ba989ecdSjsg saa.caps |= SMC_CAPS_8BIT_MODE;
453ba989ecdSjsg if (width >= 4)
454ba989ecdSjsg saa.caps |= SMC_CAPS_4BIT_MODE;
4558eda2d14Spatrick
4568eda2d14Spatrick sc->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
4578eda2d14Spatrick if (sc->sdmmc == NULL) {
4586ceec144Ssyl printf("%s: can't attach sdmmc\n", DEVNAME(sc));
4598eda2d14Spatrick goto err;
4608eda2d14Spatrick }
4618eda2d14Spatrick
4628eda2d14Spatrick return;
4638eda2d14Spatrick err:
4646ceec144Ssyl if (sc->sc_ih != NULL)
4656ceec144Ssyl arm_intr_disestablish(sc->sc_ih);
466d6b0164cSjsg bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
4678eda2d14Spatrick }
4688eda2d14Spatrick
4698eda2d14Spatrick
4708eda2d14Spatrick /*
4718eda2d14Spatrick * Power hook established by or called from attachment driver.
4728eda2d14Spatrick */
4738eda2d14Spatrick void
ommmc_power(int why,void * arg)4748eda2d14Spatrick ommmc_power(int why, void *arg)
4758eda2d14Spatrick {
4768eda2d14Spatrick #if 0
4778eda2d14Spatrick struct ommmc_softc *sc = arg;
4788eda2d14Spatrick int n, i;
4798eda2d14Spatrick #endif
4808eda2d14Spatrick
4818eda2d14Spatrick switch(why) {
4828eda2d14Spatrick case DVACT_SUSPEND:
4838eda2d14Spatrick /* XXX poll for command completion or suspend command
4848eda2d14Spatrick * in progress */
4858eda2d14Spatrick
4868eda2d14Spatrick /* Save the host controller state. */
4878eda2d14Spatrick #if 0
4888eda2d14Spatrick for (i = 0; i < sizeof sc->regs; i++)
4898eda2d14Spatrick sc->regs[i] = HREAD1(sc, i);
4908eda2d14Spatrick #endif
4918eda2d14Spatrick break;
4928eda2d14Spatrick
4938eda2d14Spatrick case DVACT_RESUME:
4948eda2d14Spatrick /* Restore the host controller state. */
4958eda2d14Spatrick #if 0
4968eda2d14Spatrick (void)ommmc_host_reset(sc);
4978eda2d14Spatrick for (i = 0; i < sizeof sc->regs; i++)
4988eda2d14Spatrick HWRITE1(sc, i, sc->regs[i]);
4998eda2d14Spatrick #endif
5008eda2d14Spatrick break;
5018eda2d14Spatrick }
5028eda2d14Spatrick }
5038eda2d14Spatrick
5048eda2d14Spatrick /*
5058eda2d14Spatrick * Shutdown hook established by or called from attachment driver.
5068eda2d14Spatrick */
5078eda2d14Spatrick void
ommmc_shutdown(void * arg)5088eda2d14Spatrick ommmc_shutdown(void *arg)
5098eda2d14Spatrick {
5108eda2d14Spatrick struct ommmc_softc *sc = arg;
5118eda2d14Spatrick
5128eda2d14Spatrick /* XXX chip locks up if we don't disable it before reboot. */
5138eda2d14Spatrick (void)ommmc_host_reset(sc);
5148eda2d14Spatrick }
5158eda2d14Spatrick
5168eda2d14Spatrick /*
5178eda2d14Spatrick * Reset the host controller. Called during initialization, when
5188eda2d14Spatrick * cards are removed, upon resume, and during error recovery.
5198eda2d14Spatrick */
5208eda2d14Spatrick int
ommmc_host_reset(sdmmc_chipset_handle_t sch)5218eda2d14Spatrick ommmc_host_reset(sdmmc_chipset_handle_t sch)
5228eda2d14Spatrick {
5238eda2d14Spatrick struct ommmc_softc *sc = sch;
5241d4cb177Ssyl uint32_t imask;
5258eda2d14Spatrick int error;
5268eda2d14Spatrick int s;
5278eda2d14Spatrick
5288eda2d14Spatrick s = splsdmmc();
5298eda2d14Spatrick
5308eda2d14Spatrick /* Disable all interrupts. */
5318eda2d14Spatrick HWRITE4(sc, MMCHS_IE, 0);
5328eda2d14Spatrick HWRITE4(sc, MMCHS_ISE, 0);
5338eda2d14Spatrick
5348eda2d14Spatrick /*
5358eda2d14Spatrick * Reset the entire host controller and wait up to 100ms for
5368eda2d14Spatrick * the controller to clear the reset bit.
5378eda2d14Spatrick */
5388eda2d14Spatrick if ((error = ommmc_soft_reset(sc, MMCHS_SYSCTL_SRA)) != 0) {
5398eda2d14Spatrick splx(s);
5408eda2d14Spatrick return (error);
5418eda2d14Spatrick }
5428eda2d14Spatrick
5438eda2d14Spatrick #if 0
5448eda2d14Spatrick HSET4(sc, MMCHS_CON, MMCHS_CON_INIT);
5458eda2d14Spatrick HWRITE4(sc, MMCHS_CMD, 0);
5468eda2d14Spatrick delay(100); /* should delay 1ms */
5478eda2d14Spatrick
5488eda2d14Spatrick HWRITE4(sc, MMCHS_STAT, MMCHS_STAT_CC);
5498eda2d14Spatrick HCLR4(sc, MMCHS_CON, MMCHS_CON_INIT);
5508eda2d14Spatrick HWRITE4(sc, MMCHS_STAT, ~0);
5518eda2d14Spatrick #endif
5528eda2d14Spatrick
5538eda2d14Spatrick
5548eda2d14Spatrick /* Set data timeout counter value to max for now. */
5558eda2d14Spatrick HSET4(sc, MMCHS_SYSCTL, 0xe << MMCHS_SYSCTL_DTO_SH);
5568eda2d14Spatrick
5578eda2d14Spatrick /* Enable interrupts. */
5588eda2d14Spatrick imask = MMCHS_STAT_BRR | MMCHS_STAT_BWR | MMCHS_STAT_BGE |
5598eda2d14Spatrick MMCHS_STAT_TC | MMCHS_STAT_CC;
5608eda2d14Spatrick
5618eda2d14Spatrick imask |= MMCHS_STAT_BADA | MMCHS_STAT_CERR | MMCHS_STAT_DEB |
5628eda2d14Spatrick MMCHS_STAT_DCRC | MMCHS_STAT_DTO | MMCHS_STAT_CIE |
5638eda2d14Spatrick MMCHS_STAT_CEB | MMCHS_STAT_CCRC | MMCHS_STAT_CTO;
5648eda2d14Spatrick
5658eda2d14Spatrick HWRITE4(sc, MMCHS_IE, imask);
5668eda2d14Spatrick HWRITE4(sc, MMCHS_ISE, imask);
5678eda2d14Spatrick
568fd7711bbSjsg /* Switch back to 1-bit bus. */
569fd7711bbSjsg HCLR4(sc, MMCHS_CON, MMCHS_CON_DW8);
570fd7711bbSjsg HCLR4(sc, MMCHS_HCTL, MMCHS_HCTL_DTW);
571fd7711bbSjsg
5728eda2d14Spatrick splx(s);
57334b1a93aSsyl return (0);
5748eda2d14Spatrick }
5758eda2d14Spatrick
5768eda2d14Spatrick uint32_t
ommmc_host_ocr(sdmmc_chipset_handle_t sch)5778eda2d14Spatrick ommmc_host_ocr(sdmmc_chipset_handle_t sch)
5788eda2d14Spatrick {
5798eda2d14Spatrick struct ommmc_softc *sc = sch;
58034b1a93aSsyl return (sc->ocr);
5818eda2d14Spatrick }
5828eda2d14Spatrick
5838eda2d14Spatrick int
ommmc_host_maxblklen(sdmmc_chipset_handle_t sch)5848eda2d14Spatrick ommmc_host_maxblklen(sdmmc_chipset_handle_t sch)
5858eda2d14Spatrick {
5868eda2d14Spatrick struct ommmc_softc *sc = sch;
58734b1a93aSsyl return (sc->maxblklen);
5888eda2d14Spatrick }
5898eda2d14Spatrick
5908eda2d14Spatrick /*
5918eda2d14Spatrick * Return non-zero if the card is currently inserted.
5928eda2d14Spatrick */
5938eda2d14Spatrick int
ommmc_card_detect(sdmmc_chipset_handle_t sch)5948eda2d14Spatrick ommmc_card_detect(sdmmc_chipset_handle_t sch)
5958eda2d14Spatrick {
5968eda2d14Spatrick struct ommmc_softc *sc = sch;
5971700f686Skettenis
5981700f686Skettenis if (OF_getproplen(sc->sc_node, "non-removable") == 0)
5991700f686Skettenis return 1;
6001700f686Skettenis
6011700f686Skettenis if (sc->sc_gpio[0]) {
6021700f686Skettenis int inverted, val;
6031700f686Skettenis
6041700f686Skettenis val = gpio_controller_get_pin(sc->sc_gpio);
6051700f686Skettenis
6061700f686Skettenis inverted = (OF_getproplen(sc->sc_node, "cd-inverted") == 0);
6071700f686Skettenis return inverted ? !val : val;
6081700f686Skettenis }
6091700f686Skettenis
610b746bbf9Sfgsch return !ISSET(HREAD4(sc, MMCHS_SYSTEST), MMCHS_SYSTEST_SDCD) ?
6118eda2d14Spatrick 1 : 0;
6128eda2d14Spatrick }
6138eda2d14Spatrick
6148eda2d14Spatrick /*
6158eda2d14Spatrick * Set or change SD bus voltage and enable or disable SD bus power.
6168eda2d14Spatrick * Return zero on success.
6178eda2d14Spatrick */
6188eda2d14Spatrick int
ommmc_bus_power(sdmmc_chipset_handle_t sch,uint32_t ocr)6198eda2d14Spatrick ommmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
6208eda2d14Spatrick {
6218eda2d14Spatrick struct ommmc_softc *sc = sch;
6228eda2d14Spatrick uint32_t vdd;
6238eda2d14Spatrick uint32_t reg;
6248eda2d14Spatrick int s;
6258eda2d14Spatrick
6268eda2d14Spatrick s = splsdmmc();
6278eda2d14Spatrick
6288eda2d14Spatrick /*
6298eda2d14Spatrick * Disable bus power before voltage change.
6308eda2d14Spatrick */
6318eda2d14Spatrick HCLR4(sc, MMCHS_HCTL, MMCHS_HCTL_SDBP);
6328eda2d14Spatrick
6338eda2d14Spatrick /* If power is disabled, reset the host and return now. */
6348eda2d14Spatrick if (ocr == 0) {
6358eda2d14Spatrick splx(s);
6368eda2d14Spatrick (void)ommmc_host_reset(sc);
63734b1a93aSsyl return (0);
6388eda2d14Spatrick }
6398eda2d14Spatrick
6408eda2d14Spatrick /*
6418eda2d14Spatrick * Select the maximum voltage according to capabilities.
6428eda2d14Spatrick */
6438eda2d14Spatrick ocr &= sc->ocr;
6448eda2d14Spatrick
6458eda2d14Spatrick if (ISSET(ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V))
6468eda2d14Spatrick vdd = MMCHS_HCTL_SDVS_V33;
6478eda2d14Spatrick else if (ISSET(ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V))
6488eda2d14Spatrick vdd = MMCHS_HCTL_SDVS_V30;
649b676d50fSkettenis else if (ISSET(ocr, MMC_OCR_1_65V_1_95V))
6508eda2d14Spatrick vdd = MMCHS_HCTL_SDVS_V18;
6518eda2d14Spatrick else {
6528eda2d14Spatrick /* Unsupported voltage level requested. */
6538eda2d14Spatrick splx(s);
65434b1a93aSsyl return (EINVAL);
6558eda2d14Spatrick }
6568eda2d14Spatrick
6578eda2d14Spatrick /*
6588eda2d14Spatrick * Enable bus power. Wait at least 1 ms (or 74 clocks) plus
6598eda2d14Spatrick * voltage ramp until power rises.
6608eda2d14Spatrick */
6618eda2d14Spatrick reg = HREAD4(sc, MMCHS_HCTL);
6627d32c5c3Srapha reg &= ~MMCHS_HCTL_SDVS_MASK;
6637d32c5c3Srapha reg |= vdd;
6648eda2d14Spatrick HWRITE4(sc, MMCHS_HCTL, reg);
6658eda2d14Spatrick
6668eda2d14Spatrick HSET4(sc, MMCHS_HCTL, MMCHS_HCTL_SDBP);
6678eda2d14Spatrick delay(10000); /* XXX */
6688eda2d14Spatrick
6698eda2d14Spatrick /*
6708eda2d14Spatrick * The host system may not power the bus due to battery low,
6718eda2d14Spatrick * etc. In that case, the host controller should clear the
6728eda2d14Spatrick * bus power bit.
6738eda2d14Spatrick */
6748eda2d14Spatrick if (!ISSET(HREAD4(sc, MMCHS_HCTL), MMCHS_HCTL_SDBP)) {
6758eda2d14Spatrick splx(s);
67634b1a93aSsyl return (ENXIO);
6778eda2d14Spatrick }
6788eda2d14Spatrick
6798eda2d14Spatrick splx(s);
68034b1a93aSsyl return (0);
6818eda2d14Spatrick }
6828eda2d14Spatrick
6838eda2d14Spatrick /*
6848eda2d14Spatrick * Return the smallest possible base clock frequency divisor value
6852252d02cSkettenis * for the CLOCK_CTL register to produce `freq' (kHz).
6868eda2d14Spatrick */
6878eda2d14Spatrick static int
ommmc_clock_divisor(struct ommmc_softc * sc,uint32_t freq)6881d4cb177Ssyl ommmc_clock_divisor(struct ommmc_softc *sc, uint32_t freq)
6898eda2d14Spatrick {
6908eda2d14Spatrick int div;
6918eda2d14Spatrick uint32_t maxclk = MMCHS_SYSCTL_CLKD_MASK>>MMCHS_SYSCTL_CLKD_SH;
6928eda2d14Spatrick
6938eda2d14Spatrick for (div = 1; div <= maxclk; div++)
6948eda2d14Spatrick if ((sc->clkbase / div) <= freq) {
6958eda2d14Spatrick return (div);
6968eda2d14Spatrick }
6978eda2d14Spatrick
6988eda2d14Spatrick printf("divisor failure\n");
6998eda2d14Spatrick /* No divisor found. */
70034b1a93aSsyl return (-1);
7018eda2d14Spatrick }
7028eda2d14Spatrick
7038eda2d14Spatrick /*
7048eda2d14Spatrick * Set or change SDCLK frequency or disable the SD clock.
7058eda2d14Spatrick * Return zero on success.
7068eda2d14Spatrick */
7078eda2d14Spatrick int
ommmc_bus_clock(sdmmc_chipset_handle_t sch,int freq,int timing)708820e06f1Skettenis ommmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing)
7098eda2d14Spatrick {
7108eda2d14Spatrick int error = 0;
7118eda2d14Spatrick struct ommmc_softc *sc = sch;
7128eda2d14Spatrick uint32_t reg;
7138eda2d14Spatrick int s;
7148eda2d14Spatrick int div;
7158eda2d14Spatrick int timo;
7168eda2d14Spatrick
7178eda2d14Spatrick s = splsdmmc();
7188eda2d14Spatrick
7198eda2d14Spatrick /* Must not stop the clock if commands are in progress. */
7207d32c5c3Srapha for (timo = 1000; timo > 0; timo--) {
7217d32c5c3Srapha if (!ISSET(HREAD4(sc, MMCHS_PSTATE),
7227d32c5c3Srapha MMCHS_PSTATE_CMDI|MMCHS_PSTATE_DATI))
7237d32c5c3Srapha break;
7247d32c5c3Srapha delay(10);
7257d32c5c3Srapha }
7267d32c5c3Srapha if (timo == 0) {
7277d32c5c3Srapha error = ETIMEDOUT;
7287d32c5c3Srapha goto ret;
7297d32c5c3Srapha }
7308eda2d14Spatrick
7318eda2d14Spatrick /*
7328eda2d14Spatrick * Stop SD clock before changing the frequency.
7338eda2d14Spatrick */
7348eda2d14Spatrick HCLR4(sc, MMCHS_SYSCTL, MMCHS_SYSCTL_CEN);
7358eda2d14Spatrick if (freq == SDMMC_SDCLK_OFF)
7368eda2d14Spatrick goto ret;
7378eda2d14Spatrick
7388eda2d14Spatrick /*
7398eda2d14Spatrick * Set the minimum base clock frequency divisor.
7408eda2d14Spatrick */
7418eda2d14Spatrick if ((div = ommmc_clock_divisor(sc, freq)) < 0) {
7428eda2d14Spatrick /* Invalid base clock frequency or `freq' value. */
7438eda2d14Spatrick error = EINVAL;
7448eda2d14Spatrick goto ret;
7458eda2d14Spatrick }
7468eda2d14Spatrick reg = HREAD4(sc, MMCHS_SYSCTL);
7478eda2d14Spatrick reg &= ~MMCHS_SYSCTL_CLKD_MASK;
7488eda2d14Spatrick reg |= div << MMCHS_SYSCTL_CLKD_SH;
7498eda2d14Spatrick HWRITE4(sc, MMCHS_SYSCTL, reg);
7508eda2d14Spatrick
751ba989ecdSjsg if ((timing == SDMMC_TIMING_HIGHSPEED) && (sc->sc_flags & FL_HSS))
752ba3fe1deSjsg HSET4(sc, MMCHS_HCTL, MMCHS_HCTL_HSPE);
753ba989ecdSjsg else
754ba989ecdSjsg HCLR4(sc, MMCHS_HCTL, MMCHS_HCTL_HSPE);
755ba3fe1deSjsg
7568eda2d14Spatrick /*
7578eda2d14Spatrick * Start internal clock. Wait 10ms for stabilization.
7588eda2d14Spatrick */
7598eda2d14Spatrick HSET4(sc, MMCHS_SYSCTL, MMCHS_SYSCTL_ICE);
7608eda2d14Spatrick for (timo = 1000; timo > 0; timo--) {
7618eda2d14Spatrick if (ISSET(HREAD4(sc, MMCHS_SYSCTL), MMCHS_SYSCTL_ICS))
7628eda2d14Spatrick break;
7638eda2d14Spatrick delay(10);
7648eda2d14Spatrick }
7658eda2d14Spatrick if (timo == 0) {
7668eda2d14Spatrick error = ETIMEDOUT;
7678eda2d14Spatrick goto ret;
7688eda2d14Spatrick }
7698eda2d14Spatrick
7708eda2d14Spatrick /*
7718eda2d14Spatrick * Enable SD clock.
7728eda2d14Spatrick */
7738eda2d14Spatrick HSET4(sc, MMCHS_SYSCTL, MMCHS_SYSCTL_CEN);
7748eda2d14Spatrick ret:
7758eda2d14Spatrick splx(s);
77634b1a93aSsyl return (error);
7778eda2d14Spatrick }
7788eda2d14Spatrick
779e44746dcSjsg int
ommmc_bus_width(sdmmc_chipset_handle_t sch,int width)780e44746dcSjsg ommmc_bus_width(sdmmc_chipset_handle_t sch, int width)
781e44746dcSjsg {
782e44746dcSjsg struct ommmc_softc *sc = sch;
783e44746dcSjsg int s;
784e44746dcSjsg
785e44746dcSjsg if (width != 1 && width != 4 && width != 8)
786e44746dcSjsg return (1);
787e44746dcSjsg
788e44746dcSjsg s = splsdmmc();
789e44746dcSjsg
790e44746dcSjsg if (width == 8)
791e44746dcSjsg HSET4(sc, MMCHS_CON, MMCHS_CON_DW8);
792e44746dcSjsg else
793e44746dcSjsg HCLR4(sc, MMCHS_CON, MMCHS_CON_DW8);
794e44746dcSjsg
795e44746dcSjsg if (width == 4)
796e44746dcSjsg HSET4(sc, MMCHS_HCTL, MMCHS_HCTL_DTW);
797e44746dcSjsg else if (width == 1)
798e44746dcSjsg HCLR4(sc, MMCHS_HCTL, MMCHS_HCTL_DTW);
799e44746dcSjsg
800e44746dcSjsg splx(s);
801e44746dcSjsg
802e44746dcSjsg return (0);
803e44746dcSjsg }
804e44746dcSjsg
8058eda2d14Spatrick void
ommmc_card_intr_mask(sdmmc_chipset_handle_t sch,int enable)8068eda2d14Spatrick ommmc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
8078eda2d14Spatrick {
8088eda2d14Spatrick /* - this is SDIO card interrupt */
8098eda2d14Spatrick struct ommmc_softc *sc = sch;
8108eda2d14Spatrick
8118eda2d14Spatrick if (enable) {
8128eda2d14Spatrick HSET4(sc, MMCHS_IE, MMCHS_STAT_CIRQ);
8138eda2d14Spatrick HSET4(sc, MMCHS_ISE, MMCHS_STAT_CIRQ);
8148eda2d14Spatrick } else {
8158eda2d14Spatrick HCLR4(sc, MMCHS_IE, MMCHS_STAT_CIRQ);
8168eda2d14Spatrick HCLR4(sc, MMCHS_ISE, MMCHS_STAT_CIRQ);
8178eda2d14Spatrick }
8188eda2d14Spatrick }
8198eda2d14Spatrick
8208eda2d14Spatrick void
ommmc_card_intr_ack(sdmmc_chipset_handle_t sch)8218eda2d14Spatrick ommmc_card_intr_ack(sdmmc_chipset_handle_t sch)
8228eda2d14Spatrick {
8238eda2d14Spatrick struct ommmc_softc *sc = sch;
8248eda2d14Spatrick
8258eda2d14Spatrick HWRITE4(sc, MMCHS_STAT, MMCHS_STAT_CIRQ);
8268eda2d14Spatrick }
8278eda2d14Spatrick
8288eda2d14Spatrick int
ommmc_wait_state(struct ommmc_softc * sc,uint32_t mask,uint32_t value)8298eda2d14Spatrick ommmc_wait_state(struct ommmc_softc *sc, uint32_t mask, uint32_t value)
8308eda2d14Spatrick {
8318eda2d14Spatrick uint32_t state;
8328eda2d14Spatrick int timeout;
8338eda2d14Spatrick
8348eda2d14Spatrick state = HREAD4(sc, MMCHS_PSTATE);
8358c9b4ef8Ssyl DPRINTF(3,("%s: wait_state %x %x %x(state=%b)\n", DEVNAME(sc),
8368eda2d14Spatrick mask, value, state, state, MMCHS_PSTATE_FMT));
8378eda2d14Spatrick for (timeout = 1000; timeout > 0; timeout--) {
8388eda2d14Spatrick if (((state = HREAD4(sc, MMCHS_PSTATE)) & mask) == value)
83934b1a93aSsyl return (0);
8408eda2d14Spatrick delay(10);
8418eda2d14Spatrick }
8428c9b4ef8Ssyl DPRINTF(0,("%s: timeout waiting for %x (state=%b)\n", DEVNAME(sc),
8438eda2d14Spatrick value, state, MMCHS_PSTATE_FMT));
84434b1a93aSsyl return (ETIMEDOUT);
8458eda2d14Spatrick }
8468eda2d14Spatrick
8478eda2d14Spatrick void
ommmc_exec_command(sdmmc_chipset_handle_t sch,struct sdmmc_command * cmd)8488eda2d14Spatrick ommmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
8498eda2d14Spatrick {
8508eda2d14Spatrick struct ommmc_softc *sc = sch;
8518eda2d14Spatrick int error;
8528eda2d14Spatrick
8538eda2d14Spatrick /*
8548eda2d14Spatrick * Start the MMC command, or mark `cmd' as failed and return.
8558eda2d14Spatrick */
8568eda2d14Spatrick error = ommmc_start_command(sc, cmd);
8578eda2d14Spatrick if (error != 0) {
8588eda2d14Spatrick cmd->c_error = error;
8598eda2d14Spatrick SET(cmd->c_flags, SCF_ITSDONE);
8608eda2d14Spatrick return;
8618eda2d14Spatrick }
8628eda2d14Spatrick
8638eda2d14Spatrick /*
8648eda2d14Spatrick * Wait until the command phase is done, or until the command
8658eda2d14Spatrick * is marked done for any other reason.
8668eda2d14Spatrick */
8678eda2d14Spatrick if (!ommmc_wait_intr(sc, MMCHS_STAT_CC, SDHC_COMMAND_TIMEOUT)) {
8688eda2d14Spatrick cmd->c_error = ETIMEDOUT;
8698eda2d14Spatrick SET(cmd->c_flags, SCF_ITSDONE);
8708eda2d14Spatrick return;
8718eda2d14Spatrick }
8728eda2d14Spatrick
8738eda2d14Spatrick /*
8748eda2d14Spatrick * The host controller removes bits [0:7] from the response
8758eda2d14Spatrick * data (CRC) and we pass the data up unchanged to the bus
8768eda2d14Spatrick * driver (without padding).
8778eda2d14Spatrick */
8788eda2d14Spatrick if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
8798eda2d14Spatrick if (ISSET(cmd->c_flags, SCF_RSP_136)) {
8808eda2d14Spatrick uint32_t v0,v1,v2,v3;
8818eda2d14Spatrick v0 = HREAD4(sc, MMCHS_RSP10);
8828eda2d14Spatrick v1 = HREAD4(sc, MMCHS_RSP32);
8838eda2d14Spatrick v2 = HREAD4(sc, MMCHS_RSP54);
8848eda2d14Spatrick v3 = HREAD4(sc, MMCHS_RSP76);
8858eda2d14Spatrick
8868eda2d14Spatrick cmd->c_resp[0] = (v0 >> 8) | ((v1 & 0xff) << 24);
8878eda2d14Spatrick cmd->c_resp[1] = (v1 >> 8) | ((v2 & 0xff) << 24);
8888eda2d14Spatrick cmd->c_resp[2] = (v2 >> 8) | ((v3 & 0xff) << 24);
8898eda2d14Spatrick cmd->c_resp[3] = v3 >> 8;
8908eda2d14Spatrick #ifdef SDHC_DEBUG
8918eda2d14Spatrick printf("resp[0] 0x%08x\nresp[1] 0x%08x\nresp[2] 0x%08x\nresp[3] 0x%08x\n", cmd->c_resp[0], cmd->c_resp[1], cmd->c_resp[2], cmd->c_resp[3]);
8928eda2d14Spatrick #endif
8938eda2d14Spatrick } else {
8948eda2d14Spatrick cmd->c_resp[0] = HREAD4(sc, MMCHS_RSP10);
8958eda2d14Spatrick #ifdef SDHC_DEBUG
8968eda2d14Spatrick printf("resp[0] 0x%08x\n", cmd->c_resp[0]);
8978eda2d14Spatrick #endif
8988eda2d14Spatrick }
8998eda2d14Spatrick }
9008eda2d14Spatrick
9018eda2d14Spatrick /*
9028eda2d14Spatrick * If the command has data to transfer in any direction,
9038eda2d14Spatrick * execute the transfer now.
9048eda2d14Spatrick */
9058eda2d14Spatrick if (cmd->c_error == 0 && cmd->c_data != NULL)
9068eda2d14Spatrick ommmc_transfer_data(sc, cmd);
9078eda2d14Spatrick
9088eda2d14Spatrick #if 0
9098eda2d14Spatrick /* Turn off the LED. */
9108eda2d14Spatrick HCLR1(sc, SDHC_HOST_CTL, SDHC_LED_ON);
9118eda2d14Spatrick #endif
9128eda2d14Spatrick
9138eda2d14Spatrick DPRINTF(1,("%s: cmd %u done (flags=%#x error=%d)\n",
9148c9b4ef8Ssyl DEVNAME(sc), cmd->c_opcode, cmd->c_flags, cmd->c_error));
9158eda2d14Spatrick SET(cmd->c_flags, SCF_ITSDONE);
9168eda2d14Spatrick }
9178eda2d14Spatrick
9188eda2d14Spatrick int
ommmc_start_command(struct ommmc_softc * sc,struct sdmmc_command * cmd)9198eda2d14Spatrick ommmc_start_command(struct ommmc_softc *sc, struct sdmmc_command *cmd)
9208eda2d14Spatrick {
9211d4cb177Ssyl uint32_t blksize = 0;
9221d4cb177Ssyl uint32_t blkcount = 0;
9231d4cb177Ssyl uint32_t command;
9248eda2d14Spatrick int error;
9258eda2d14Spatrick int s;
9268eda2d14Spatrick
9271dd2d335Sians DPRINTF(1,("%s: start cmd %u arg=%#x data=%p dlen=%d flags=%#x\n",
9281dd2d335Sians DEVNAME(sc), cmd->c_opcode, cmd->c_arg, cmd->c_data,
9291dd2d335Sians cmd->c_datalen, cmd->c_flags));
9308eda2d14Spatrick
9318eda2d14Spatrick /*
9328eda2d14Spatrick * The maximum block length for commands should be the minimum
9338eda2d14Spatrick * of the host buffer size and the card buffer size. (1.7.2)
9348eda2d14Spatrick */
9358eda2d14Spatrick
9368eda2d14Spatrick /* Fragment the data into proper blocks. */
9378eda2d14Spatrick if (cmd->c_datalen > 0) {
9388eda2d14Spatrick blksize = MIN(cmd->c_datalen, cmd->c_blklen);
9398eda2d14Spatrick blkcount = cmd->c_datalen / blksize;
9408eda2d14Spatrick if (cmd->c_datalen % blksize > 0) {
9418eda2d14Spatrick /* XXX: Split this command. (1.7.4) */
9428eda2d14Spatrick printf("%s: data not a multiple of %d bytes\n",
9438c9b4ef8Ssyl DEVNAME(sc), blksize);
94434b1a93aSsyl return (EINVAL);
9458eda2d14Spatrick }
9468eda2d14Spatrick }
9478eda2d14Spatrick
9488eda2d14Spatrick /* Check limit imposed by 9-bit block count. (1.7.2) */
9498eda2d14Spatrick if (blkcount > MMCHS_BLK_NBLK_MAX) {
9508c9b4ef8Ssyl printf("%s: too much data\n", DEVNAME(sc));
95134b1a93aSsyl return (EINVAL);
9528eda2d14Spatrick }
9538eda2d14Spatrick
9548eda2d14Spatrick /* Prepare transfer mode register value. (2.2.5) */
9558eda2d14Spatrick command = 0;
9568eda2d14Spatrick if (ISSET(cmd->c_flags, SCF_CMD_READ))
9578eda2d14Spatrick command |= MMCHS_CMD_DDIR;
9588eda2d14Spatrick if (blkcount > 0) {
9598eda2d14Spatrick command |= MMCHS_CMD_BCE;
9608eda2d14Spatrick if (blkcount > 1) {
9618eda2d14Spatrick command |= MMCHS_CMD_MSBS;
9628eda2d14Spatrick /* XXX only for memory commands? */
9638eda2d14Spatrick command |= MMCHS_CMD_ACEN;
9648eda2d14Spatrick }
9658eda2d14Spatrick }
9668eda2d14Spatrick #ifdef notyet
9678eda2d14Spatrick if (ISSET(sc->flags, SHF_USE_DMA))
9688eda2d14Spatrick command |= MMCHS_CMD_DE;
9698eda2d14Spatrick #endif
9708eda2d14Spatrick
9718eda2d14Spatrick /*
9728eda2d14Spatrick * Prepare command register value. (2.2.6)
9738eda2d14Spatrick */
9748eda2d14Spatrick command |= (cmd->c_opcode << MMCHS_CMD_INDX_SHIFT) &
9758eda2d14Spatrick MMCHS_CMD_INDX_SHIFT_MASK;
9768eda2d14Spatrick
9778eda2d14Spatrick if (ISSET(cmd->c_flags, SCF_RSP_CRC))
9788eda2d14Spatrick command |= MMCHS_CMD_CCCE;
9798eda2d14Spatrick if (ISSET(cmd->c_flags, SCF_RSP_IDX))
9808eda2d14Spatrick command |= MMCHS_CMD_CICE;
9818eda2d14Spatrick if (cmd->c_data != NULL)
9828eda2d14Spatrick command |= MMCHS_CMD_DP;
9838eda2d14Spatrick
9848eda2d14Spatrick if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
9858eda2d14Spatrick command |= MMCHS_CMD_RESP_NONE;
9868eda2d14Spatrick else if (ISSET(cmd->c_flags, SCF_RSP_136))
9878eda2d14Spatrick command |= MMCHS_CMD_RESP136;
9888eda2d14Spatrick else if (ISSET(cmd->c_flags, SCF_RSP_BSY))
9898eda2d14Spatrick command |= MMCHS_CMD_RESP48B;
9908eda2d14Spatrick else
9918eda2d14Spatrick command |= MMCHS_CMD_RESP48;
9928eda2d14Spatrick
9938eda2d14Spatrick /* Wait until command and data inhibit bits are clear. (1.5) */
9948eda2d14Spatrick if ((error = ommmc_wait_state(sc, MMCHS_PSTATE_CMDI, 0)) != 0)
99534b1a93aSsyl return (error);
9968eda2d14Spatrick
9978eda2d14Spatrick s = splsdmmc();
9988eda2d14Spatrick
9998eda2d14Spatrick #if 0
10008eda2d14Spatrick /* Alert the user not to remove the card. */
10018eda2d14Spatrick HSET1(sc, SDHC_HOST_CTL, SDHC_LED_ON);
10028eda2d14Spatrick #endif
10038eda2d14Spatrick
10048eda2d14Spatrick /* XXX: Set DMA start address if SHF_USE_DMA is set. */
10058eda2d14Spatrick
10068eda2d14Spatrick DPRINTF(1,("%s: cmd=%#x blksize=%d blkcount=%d\n",
10078c9b4ef8Ssyl DEVNAME(sc), command, blksize, blkcount));
10088eda2d14Spatrick
10098eda2d14Spatrick /*
10108eda2d14Spatrick * Start a CPU data transfer. Writing to the high order byte
10118eda2d14Spatrick * of the SDHC_COMMAND register triggers the SD command. (1.5)
10128eda2d14Spatrick */
10138eda2d14Spatrick HWRITE4(sc, MMCHS_BLK, (blkcount << MMCHS_BLK_NBLK_SHIFT) |
10148eda2d14Spatrick (blksize << MMCHS_BLK_BLEN_SHIFT));
10158eda2d14Spatrick HWRITE4(sc, MMCHS_ARG, cmd->c_arg);
10168eda2d14Spatrick HWRITE4(sc, MMCHS_CMD, command);
10178eda2d14Spatrick
10188eda2d14Spatrick splx(s);
101934b1a93aSsyl return (0);
10208eda2d14Spatrick }
10218eda2d14Spatrick
10228eda2d14Spatrick void
ommmc_transfer_data(struct ommmc_softc * sc,struct sdmmc_command * cmd)10238eda2d14Spatrick ommmc_transfer_data(struct ommmc_softc *sc, struct sdmmc_command *cmd)
10248eda2d14Spatrick {
10251d4cb177Ssyl uint8_t *datap = cmd->c_data;
10268eda2d14Spatrick int i, datalen;
10278eda2d14Spatrick int mask;
10288eda2d14Spatrick int error;
10298eda2d14Spatrick
10308eda2d14Spatrick mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
10318eda2d14Spatrick MMCHS_PSTATE_BRE : MMCHS_PSTATE_BWE;
10328eda2d14Spatrick error = 0;
10338eda2d14Spatrick datalen = cmd->c_datalen;
10348eda2d14Spatrick
10358c9b4ef8Ssyl DPRINTF(1,("%s: resp=%#x datalen=%d\n", DEVNAME(sc),
10368eda2d14Spatrick MMC_R1(cmd->c_resp), datalen));
10378eda2d14Spatrick
10388eda2d14Spatrick while (datalen > 0) {
10398eda2d14Spatrick if (!ommmc_wait_intr(sc, MMCHS_STAT_BRR| MMCHS_STAT_BWR,
10408eda2d14Spatrick SDHC_BUFFER_TIMEOUT)) {
10418eda2d14Spatrick error = ETIMEDOUT;
10428eda2d14Spatrick break;
10438eda2d14Spatrick }
10448eda2d14Spatrick
10458eda2d14Spatrick if ((error = ommmc_wait_state(sc, mask, mask)) != 0)
10468eda2d14Spatrick break;
10478eda2d14Spatrick
10488eda2d14Spatrick i = MIN(datalen, cmd->c_blklen);
10498eda2d14Spatrick if (ISSET(cmd->c_flags, SCF_CMD_READ))
10508eda2d14Spatrick ommmc_read_data(sc, datap, i);
10518eda2d14Spatrick else
10528eda2d14Spatrick ommmc_write_data(sc, datap, i);
10538eda2d14Spatrick
10548eda2d14Spatrick datap += i;
10558eda2d14Spatrick datalen -= i;
10568eda2d14Spatrick }
10578eda2d14Spatrick
10588eda2d14Spatrick if (error == 0 && !ommmc_wait_intr(sc, MMCHS_STAT_TC,
10598eda2d14Spatrick SDHC_TRANSFER_TIMEOUT))
10608eda2d14Spatrick error = ETIMEDOUT;
10618eda2d14Spatrick
10628eda2d14Spatrick if (error != 0)
10638eda2d14Spatrick cmd->c_error = error;
10648eda2d14Spatrick SET(cmd->c_flags, SCF_ITSDONE);
10658eda2d14Spatrick
10668eda2d14Spatrick DPRINTF(1,("%s: data transfer done (error=%d)\n",
10678c9b4ef8Ssyl DEVNAME(sc), cmd->c_error));
10688eda2d14Spatrick }
10698eda2d14Spatrick
10708eda2d14Spatrick void
ommmc_read_data(struct ommmc_softc * sc,uint8_t * datap,int datalen)10711d4cb177Ssyl ommmc_read_data(struct ommmc_softc *sc, uint8_t *datap, int datalen)
10728eda2d14Spatrick {
10738eda2d14Spatrick while (datalen > 3) {
10748eda2d14Spatrick *(uint32_t *)datap = HREAD4(sc, MMCHS_DATA);
10758eda2d14Spatrick datap += 4;
10768eda2d14Spatrick datalen -= 4;
10778eda2d14Spatrick }
10788eda2d14Spatrick if (datalen > 0) {
10798eda2d14Spatrick uint32_t rv = HREAD4(sc, MMCHS_DATA);
10808eda2d14Spatrick do {
10818eda2d14Spatrick *datap++ = rv & 0xff;
10828eda2d14Spatrick rv = rv >> 8;
10838eda2d14Spatrick } while (--datalen > 0);
10848eda2d14Spatrick }
10858eda2d14Spatrick }
10868eda2d14Spatrick
10878eda2d14Spatrick void
ommmc_write_data(struct ommmc_softc * sc,uint8_t * datap,int datalen)10881d4cb177Ssyl ommmc_write_data(struct ommmc_softc *sc, uint8_t *datap, int datalen)
10898eda2d14Spatrick {
10908eda2d14Spatrick while (datalen > 3) {
10918eda2d14Spatrick DPRINTF(3,("%08x\n", *(uint32_t *)datap));
10928eda2d14Spatrick HWRITE4(sc, MMCHS_DATA, *((uint32_t *)datap));
10938eda2d14Spatrick datap += 4;
10948eda2d14Spatrick datalen -= 4;
10958eda2d14Spatrick }
10968eda2d14Spatrick if (datalen > 0) {
10978eda2d14Spatrick uint32_t rv = *datap++;
10988eda2d14Spatrick if (datalen > 1)
10998eda2d14Spatrick rv |= *datap++ << 8;
11008eda2d14Spatrick if (datalen > 2)
11018eda2d14Spatrick rv |= *datap++ << 16;
11028eda2d14Spatrick DPRINTF(3,("rv %08x\n", rv));
11038eda2d14Spatrick HWRITE4(sc, MMCHS_DATA, rv);
11048eda2d14Spatrick }
11058eda2d14Spatrick }
11068eda2d14Spatrick
11078eda2d14Spatrick /* Prepare for another command. */
11088eda2d14Spatrick int
ommmc_soft_reset(struct ommmc_softc * sc,int mask)11098eda2d14Spatrick ommmc_soft_reset(struct ommmc_softc *sc, int mask)
11108eda2d14Spatrick {
11118eda2d14Spatrick
11128eda2d14Spatrick int timo;
11138eda2d14Spatrick
11148c9b4ef8Ssyl DPRINTF(1,("%s: software reset reg=%#x\n", DEVNAME(sc), mask));
11158eda2d14Spatrick
11168eda2d14Spatrick HSET4(sc, MMCHS_SYSCTL, mask);
1117356107beSjsg /*
1118356107beSjsg * If we read the software reset register too fast after writing it we
1119356107beSjsg * can get back a zero that means the reset hasn't started yet rather
1120356107beSjsg * than that the reset is complete. Per TI recommendations, work around
1121356107beSjsg * it by reading until we see the reset bit asserted, then read until
1122356107beSjsg * it's clear.
1123356107beSjsg */
1124356107beSjsg for (timo = 1000; timo > 0; timo--) {
1125356107beSjsg if (ISSET(HREAD4(sc, MMCHS_SYSCTL), mask))
1126356107beSjsg break;
1127356107beSjsg delay(1);
1128356107beSjsg }
11298eda2d14Spatrick for (timo = 1000; timo > 0; timo--) {
11308eda2d14Spatrick if (!ISSET(HREAD4(sc, MMCHS_SYSCTL), mask))
11318eda2d14Spatrick break;
11328eda2d14Spatrick delay(10);
11338eda2d14Spatrick }
11348eda2d14Spatrick if (timo == 0) {
11358c9b4ef8Ssyl DPRINTF(1,("%s: timeout reg=%#x\n", DEVNAME(sc),
11368eda2d14Spatrick HREAD4(sc, MMCHS_SYSCTL)));
11378eda2d14Spatrick return (ETIMEDOUT);
11388eda2d14Spatrick }
11398eda2d14Spatrick
11408eda2d14Spatrick return (0);
11418eda2d14Spatrick }
11428eda2d14Spatrick
11438eda2d14Spatrick int
ommmc_wait_intr(struct ommmc_softc * sc,int mask,int sec)114414877212Smpi ommmc_wait_intr(struct ommmc_softc *sc, int mask, int sec)
11458eda2d14Spatrick {
11468eda2d14Spatrick int status;
11478eda2d14Spatrick int s;
11488eda2d14Spatrick
11498eda2d14Spatrick mask |= MMCHS_STAT_ERRI;
11508eda2d14Spatrick
11518eda2d14Spatrick s = splsdmmc();
11528eda2d14Spatrick status = sc->intr_status & mask;
11538eda2d14Spatrick while (status == 0) {
115414877212Smpi if (tsleep_nsec(&sc->intr_status, PWAIT, "hcintr",
115514877212Smpi SEC_TO_NSEC(sec)) == EWOULDBLOCK) {
11568eda2d14Spatrick status |= MMCHS_STAT_ERRI;
11578eda2d14Spatrick break;
11588eda2d14Spatrick }
11598eda2d14Spatrick status = sc->intr_status & mask;
11608eda2d14Spatrick }
11618eda2d14Spatrick sc->intr_status &= ~status;
11628eda2d14Spatrick
11638c9b4ef8Ssyl DPRINTF(2,("%s: intr status %#x error %#x\n", DEVNAME(sc), status,
11648eda2d14Spatrick sc->intr_error_status));
11658eda2d14Spatrick
11668eda2d14Spatrick /* Command timeout has higher priority than command complete. */
11678eda2d14Spatrick if (ISSET(status, MMCHS_STAT_ERRI)) {
11688eda2d14Spatrick sc->intr_error_status = 0;
11698eda2d14Spatrick (void)ommmc_soft_reset(sc, MMCHS_SYSCTL_SRC|MMCHS_SYSCTL_SRD);
11708eda2d14Spatrick status = 0;
11718eda2d14Spatrick }
11728eda2d14Spatrick
11738eda2d14Spatrick splx(s);
117434b1a93aSsyl return (status);
11758eda2d14Spatrick }
11768eda2d14Spatrick
11778eda2d14Spatrick /*
11788eda2d14Spatrick * Established by attachment driver at interrupt priority IPL_SDMMC.
11798eda2d14Spatrick */
11808eda2d14Spatrick int
ommmc_intr(void * arg)11818eda2d14Spatrick ommmc_intr(void *arg)
11828eda2d14Spatrick {
11838eda2d14Spatrick struct ommmc_softc *sc = arg;
11848eda2d14Spatrick
11851d4cb177Ssyl uint32_t status;
11868eda2d14Spatrick
11878eda2d14Spatrick /* Find out which interrupts are pending. */
11888eda2d14Spatrick status = HREAD4(sc, MMCHS_STAT);
11898eda2d14Spatrick
11908eda2d14Spatrick /* Acknowledge the interrupts we are about to handle. */
11918eda2d14Spatrick HWRITE4(sc, MMCHS_STAT, status);
11928c9b4ef8Ssyl DPRINTF(2,("%s: interrupt status=%b\n", DEVNAME(sc),
11938eda2d14Spatrick status, MMCHS_STAT_FMT));
11948eda2d14Spatrick
11958eda2d14Spatrick /*
11968eda2d14Spatrick * Service error interrupts.
11978eda2d14Spatrick */
11988eda2d14Spatrick if (ISSET(status, MMCHS_STAT_ERRI)) {
11998eda2d14Spatrick if (ISSET(status, MMCHS_STAT_CTO|
12008eda2d14Spatrick MMCHS_STAT_DTO)) {
12018eda2d14Spatrick sc->intr_status |= status;
12028eda2d14Spatrick sc->intr_error_status |= status & 0xffff0000;
12038eda2d14Spatrick wakeup(&sc->intr_status);
12048eda2d14Spatrick }
12058eda2d14Spatrick }
12068eda2d14Spatrick
12078eda2d14Spatrick #if 0
12088eda2d14Spatrick /*
12098eda2d14Spatrick * Wake up the sdmmc event thread to scan for cards.
12108eda2d14Spatrick */
12118eda2d14Spatrick if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION))
12128eda2d14Spatrick ommmc_needs_discover(sc->sdmmc);
12138eda2d14Spatrick #endif
12148eda2d14Spatrick
12158eda2d14Spatrick /*
12168eda2d14Spatrick * Wake up the blocking process to service command
12178eda2d14Spatrick * related interrupt(s).
12188eda2d14Spatrick */
12198eda2d14Spatrick if (ISSET(status, MMCHS_STAT_BRR|
12208eda2d14Spatrick MMCHS_STAT_BWR|MMCHS_STAT_TC|
12218eda2d14Spatrick MMCHS_STAT_CC)) {
12228eda2d14Spatrick sc->intr_status |= status;
12238eda2d14Spatrick wakeup(&sc->intr_status);
12248eda2d14Spatrick }
12258eda2d14Spatrick
12268eda2d14Spatrick /*
12278eda2d14Spatrick * Service SD card interrupts.
12288eda2d14Spatrick */
12298eda2d14Spatrick if (ISSET(status, MMCHS_STAT_CIRQ)) {
12308c9b4ef8Ssyl DPRINTF(0,("%s: card interrupt\n", DEVNAME(sc)));
12318eda2d14Spatrick HCLR4(sc, MMCHS_STAT, MMCHS_STAT_CIRQ);
12328eda2d14Spatrick sdmmc_card_intr(sc->sdmmc);
12338eda2d14Spatrick }
12348eda2d14Spatrick return 1;
12358eda2d14Spatrick }
1236efdbf253Sjsg
1237efdbf253Sjsg #ifdef SDHC_DEBUG
1238efdbf253Sjsg void
ommmc_dump_regs(struct ommmc_softc * sc)1239efdbf253Sjsg ommmc_dump_regs(struct ommmc_softc *sc)
1240efdbf253Sjsg {
1241efdbf253Sjsg }
1242efdbf253Sjsg #endif
1243