xref: /openbsd-src/sys/arch/armv7/omap/ommmc.c (revision 28d09237077354eff565f9f3ef991865a249ce6c)
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