xref: /openbsd-src/sys/dev/fdt/amlmmc.c (revision 4b1a56afb1a28c97103da3911d326d1216798a6e)
1*4b1a56afSjsg /*	$OpenBSD: amlmmc.c,v 1.12 2022/01/09 05:42:37 jsg Exp $	*/
2432c5292Skettenis /*
3432c5292Skettenis  * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org>
4432c5292Skettenis  *
5432c5292Skettenis  * Permission to use, copy, modify, and distribute this software for any
6432c5292Skettenis  * purpose with or without fee is hereby granted, provided that the above
7432c5292Skettenis  * copyright notice and this permission notice appear in all copies.
8432c5292Skettenis  *
9432c5292Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10432c5292Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11432c5292Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12432c5292Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13432c5292Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14432c5292Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15432c5292Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16432c5292Skettenis  */
17432c5292Skettenis 
18432c5292Skettenis #include <sys/param.h>
19432c5292Skettenis #include <sys/systm.h>
20432c5292Skettenis #include <sys/device.h>
2158aa5fe5Skettenis #include <sys/malloc.h>
22432c5292Skettenis 
23432c5292Skettenis #include <machine/intr.h>
24432c5292Skettenis #include <machine/bus.h>
25432c5292Skettenis #include <machine/fdt.h>
26432c5292Skettenis 
27432c5292Skettenis #include <dev/ofw/openfirm.h>
28432c5292Skettenis #include <dev/ofw/ofw_clock.h>
29432c5292Skettenis #include <dev/ofw/ofw_gpio.h>
30432c5292Skettenis #include <dev/ofw/ofw_pinctrl.h>
3158aa5fe5Skettenis #include <dev/ofw/ofw_regulator.h>
32432c5292Skettenis #include <dev/ofw/fdt.h>
33432c5292Skettenis 
34432c5292Skettenis #include <dev/sdmmc/sdmmcvar.h>
35432c5292Skettenis 
36432c5292Skettenis #define SD_EMMC_CLOCK		0x0000
37a7a39a0dSkettenis #define  SD_EMMC_CLOCK_ALWAYS_ON	(1 << 28)
38432c5292Skettenis #define  SD_EMMC_CLOCK_RX_PHASE_0	(0 << 12)
39432c5292Skettenis #define  SD_EMMC_CLOCK_RX_PHASE_90	(1 << 12)
40432c5292Skettenis #define  SD_EMMC_CLOCK_RX_PHASE_180	(2 << 12)
41432c5292Skettenis #define  SD_EMMC_CLOCK_RX_PHASE_270	(3 << 12)
42432c5292Skettenis #define  SD_EMMC_CLOCK_TX_PHASE_0	(0 << 10)
43432c5292Skettenis #define  SD_EMMC_CLOCK_TX_PHASE_90	(1 << 10)
44432c5292Skettenis #define  SD_EMMC_CLOCK_TX_PHASE_180	(2 << 10)
45432c5292Skettenis #define  SD_EMMC_CLOCK_TX_PHASE_270	(3 << 10)
46432c5292Skettenis #define  SD_EMMC_CLOCK_CO_PHASE_0	(0 << 8)
47432c5292Skettenis #define  SD_EMMC_CLOCK_CO_PHASE_90	(1 << 8)
48432c5292Skettenis #define  SD_EMMC_CLOCK_CO_PHASE_180	(2 << 8)
49432c5292Skettenis #define  SD_EMMC_CLOCK_CO_PHASE_270	(3 << 8)
50432c5292Skettenis #define  SD_EMMC_CLOCK_CLK_SRC_24M	(0 << 6)
51432c5292Skettenis #define  SD_EMMC_CLOCK_CLK_SRC_FCLK	(1 << 6)
52432c5292Skettenis #define  SD_EMMC_CLOCK_DIV_MAX		63
53432c5292Skettenis #define SD_EMMC_DELAY1		0x0004
54432c5292Skettenis #define SD_EMMC_DELAY2		0x0008
55432c5292Skettenis #define SD_EMMC_ADJUST		0x000c
56a7a39a0dSkettenis #define  SD_EMMC_ADJUST_ADJ_FIXED	(1 << 13)
57a7a39a0dSkettenis #define  SD_EMMC_ADJUST_ADJ_DELAY_MASK	(0x3f << 16)
58a7a39a0dSkettenis #define  SD_EMMC_ADJUST_ADJ_DELAY_SHIFT	16
59432c5292Skettenis #define SD_EMMC_START		0x0040
6045862b87Skettenis #define  SD_EMMC_START_START		(1 << 1)
6145862b87Skettenis #define  SD_EMMC_START_STOP		(0 << 1)
62432c5292Skettenis #define SD_EMMC_CFG		0x0044
63a7a39a0dSkettenis #define  SD_EMMC_CFG_ERR_ABORT		(1 << 27)
64432c5292Skettenis #define  SD_EMMC_CFG_AUTO_CLK		(1 << 23)
6558aa5fe5Skettenis #define  SD_EMMC_CFG_STOP_CLOCK		(1 << 22)
66432c5292Skettenis #define  SD_EMMC_CFG_SDCLK_ALWAYS_ON	(1 << 18)
67432c5292Skettenis #define  SD_EMMC_CFG_RC_CC_MASK		(0xf << 12)
68432c5292Skettenis #define  SD_EMMC_CFG_RC_CC_16		(0x4 << 12)
69432c5292Skettenis #define  SD_EMMC_CFG_RESP_TIMEOUT_MASK	(0xf << 8)
70432c5292Skettenis #define  SD_EMMC_CFG_RESP_TIMEOUT_256	(0x8 << 8)
71432c5292Skettenis #define  SD_EMMC_CFG_BL_LEN_MASK	(0xf << 4)
72432c5292Skettenis #define  SD_EMMC_CFG_BL_LEN_SHIFT	4
73432c5292Skettenis #define  SD_EMMC_CFG_BL_LEN_512		(0x9 << 4)
7458aa5fe5Skettenis #define  SD_EMMC_CFG_DDR		(1 << 2)
75432c5292Skettenis #define  SD_EMMC_CFG_BUS_WIDTH_MASK	(0x3 << 0)
76432c5292Skettenis #define  SD_EMMC_CFG_BUS_WIDTH_1	(0x0 << 0)
77432c5292Skettenis #define  SD_EMMC_CFG_BUS_WIDTH_4	(0x1 << 0)
78432c5292Skettenis #define  SD_EMMC_CFG_BUS_WIDTH_8	(0x2 << 0)
79432c5292Skettenis #define SD_EMMC_STATUS		0x0048
80432c5292Skettenis #define  SD_EMMC_STATUS_END_OF_CHAIN	(1 << 13)
8192556e92Skettenis #define  SD_EMMC_STATUS_DESC_TIMEOUT	(1 << 12)
82432c5292Skettenis #define  SD_EMMC_STATUS_RESP_TIMEOUT	(1 << 11)
83432c5292Skettenis #define  SD_EMMC_STATUS_MASK		0x00003fff
8492556e92Skettenis #define  SD_EMMC_STATUS_ERR_MASK	0x000007ff
85432c5292Skettenis #define SD_EMMC_IRQ_EN		0x004c
8692556e92Skettenis #define  SD_EMMC_IRQ_EN_MASK		SD_EMMC_STATUS_MASK
87432c5292Skettenis #define SD_EMMC_CMD_CFG		0x0050
88432c5292Skettenis #define  SD_EMMC_CMD_CFG_BLOCK_MODE	(1 << 9)
89432c5292Skettenis #define  SD_EMMC_CMD_CFG_R1B		(1 << 10)
90432c5292Skettenis #define  SD_EMMC_CMD_CFG_END_OF_CHAIN	(1 << 11)
91432c5292Skettenis #define  SD_EMMC_CMD_CFG_TIMEOUT_1024	(10 << 12)
92432c5292Skettenis #define  SD_EMMC_CMD_CFG_TIMEOUT_4096	(12 << 12)
93432c5292Skettenis #define  SD_EMMC_CMD_CFG_NO_RESP	(1 << 16)
9445862b87Skettenis #define  SD_EMMC_CMD_CFG_NO_CMD		(1 << 17)
95432c5292Skettenis #define  SD_EMMC_CMD_CFG_DATA_IO	(1 << 18)
96432c5292Skettenis #define  SD_EMMC_CMD_CFG_DATA_WR	(1 << 19)
97432c5292Skettenis #define  SD_EMMC_CMD_CFG_RESP_NOCRC	(1 << 20)
98432c5292Skettenis #define  SD_EMMC_CMD_CFG_RESP_128	(1 << 21)
99432c5292Skettenis #define  SD_EMMC_CMD_CFG_CMD_INDEX_SHIFT 24
100432c5292Skettenis #define  SD_EMMC_CMD_CFG_OWNER		(1U << 31)
101432c5292Skettenis #define SD_EMMC_CMD_ARG		0x0054
102432c5292Skettenis #define SD_EMMC_CMD_DAT		0x0058
103432c5292Skettenis #define SD_EMMC_CMD_RSP		0x005c
104432c5292Skettenis #define SD_EMMC_CMD_RSP1	0x0060
105432c5292Skettenis #define SD_EMMC_CMD_RSP2	0x0064
106432c5292Skettenis #define SD_EMMC_CMD_RSP3	0x0068
107432c5292Skettenis 
108432c5292Skettenis #define HREAD4(sc, reg)							\
109432c5292Skettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
110432c5292Skettenis #define HWRITE4(sc, reg, val)						\
111432c5292Skettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
112432c5292Skettenis #define HSET4(sc, reg, bits)						\
113432c5292Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
114432c5292Skettenis #define HCLR4(sc, reg, bits)						\
115432c5292Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
116432c5292Skettenis 
117432c5292Skettenis struct amlmmc_desc {
118432c5292Skettenis 	uint32_t cmd_cfg;
119432c5292Skettenis 	uint32_t cmd_arg;
120432c5292Skettenis 	uint32_t data_addr;
121432c5292Skettenis 	uint32_t resp_addr;
122432c5292Skettenis };
123432c5292Skettenis 
12445862b87Skettenis #define AMLMMC_NDESC		(PAGE_SIZE / sizeof(struct amlmmc_desc))
125432c5292Skettenis #define AMLMMC_MAXSEGSZ		0x20000
126432c5292Skettenis 
127432c5292Skettenis struct amlmmc_softc {
128432c5292Skettenis 	struct device		sc_dev;
129432c5292Skettenis 	bus_space_tag_t		sc_iot;
130432c5292Skettenis 	bus_space_handle_t	sc_ioh;
131432c5292Skettenis 	bus_dma_tag_t		sc_dmat;
132432c5292Skettenis 	bus_dmamap_t		sc_dmap;
133432c5292Skettenis 
13492556e92Skettenis 	void			*sc_ih;
13592556e92Skettenis 	uint32_t		sc_status;
13692556e92Skettenis 
137432c5292Skettenis 	bus_dmamap_t		sc_desc_map;
138432c5292Skettenis 	bus_dma_segment_t	sc_desc_segs[1];
139432c5292Skettenis 	int			sc_desc_nsegs;
140432c5292Skettenis 	caddr_t			sc_desc;
141432c5292Skettenis 
142432c5292Skettenis 	int			sc_node;
143432c5292Skettenis 	uint32_t		sc_clkin0;
144432c5292Skettenis 	uint32_t		sc_clkin1;
145432c5292Skettenis 	uint32_t		sc_gpio[4];
14658aa5fe5Skettenis 	uint32_t		sc_vmmc;
14758aa5fe5Skettenis 	uint32_t		sc_vqmmc;
14858aa5fe5Skettenis 	uint32_t		sc_pwrseq;
14958aa5fe5Skettenis 	uint32_t		sc_vdd;
150ab6980d6Skettenis 	uint32_t		sc_ocr;
151432c5292Skettenis 
152432c5292Skettenis 	int			sc_blklen;
153432c5292Skettenis 	struct device		*sc_sdmmc;
154432c5292Skettenis };
155432c5292Skettenis 
156432c5292Skettenis int amlmmc_match(struct device *, void *, void *);
157432c5292Skettenis void amlmmc_attach(struct device *, struct device *, void *);
158432c5292Skettenis 
1599fdf0c62Smpi const struct cfattach	amlmmc_ca = {
160432c5292Skettenis 	sizeof (struct amlmmc_softc), amlmmc_match, amlmmc_attach
161432c5292Skettenis };
162432c5292Skettenis 
163432c5292Skettenis struct cfdriver amlmmc_cd = {
164432c5292Skettenis 	NULL, "amlmmc", DV_DULL
165432c5292Skettenis };
166432c5292Skettenis 
167432c5292Skettenis int	amlmmc_alloc_descriptors(struct amlmmc_softc *);
168432c5292Skettenis void	amlmmc_free_descriptors(struct amlmmc_softc *);
16992556e92Skettenis int	amlmmc_intr(void *);
170432c5292Skettenis 
17158aa5fe5Skettenis void	amlmmc_pwrseq_reset(uint32_t);
17258aa5fe5Skettenis 
173432c5292Skettenis int	amlmmc_host_reset(sdmmc_chipset_handle_t);
174432c5292Skettenis uint32_t amlmmc_host_ocr(sdmmc_chipset_handle_t);
175432c5292Skettenis int	amlmmc_host_maxblklen(sdmmc_chipset_handle_t);
176432c5292Skettenis int	amlmmc_card_detect(sdmmc_chipset_handle_t);
177432c5292Skettenis int	amlmmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
178432c5292Skettenis int	amlmmc_bus_clock(sdmmc_chipset_handle_t, int, int);
179432c5292Skettenis int	amlmmc_bus_width(sdmmc_chipset_handle_t, int);
180432c5292Skettenis void	amlmmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
18158aa5fe5Skettenis int	amlmmc_signal_voltage(sdmmc_chipset_handle_t, int);
182a7a39a0dSkettenis int	amlmmc_execute_tuning(sdmmc_chipset_handle_t, int);
183432c5292Skettenis 
184432c5292Skettenis struct sdmmc_chip_functions amlmmc_chip_functions = {
185432c5292Skettenis 	.host_reset = amlmmc_host_reset,
186432c5292Skettenis 	.host_ocr = amlmmc_host_ocr,
187432c5292Skettenis 	.host_maxblklen = amlmmc_host_maxblklen,
188432c5292Skettenis 	.card_detect = amlmmc_card_detect,
189432c5292Skettenis 	.bus_power = amlmmc_bus_power,
190432c5292Skettenis 	.bus_clock = amlmmc_bus_clock,
191432c5292Skettenis 	.bus_width = amlmmc_bus_width,
192432c5292Skettenis 	.exec_command = amlmmc_exec_command,
19358aa5fe5Skettenis 	.signal_voltage = amlmmc_signal_voltage,
194a7a39a0dSkettenis 	.execute_tuning = amlmmc_execute_tuning,
195432c5292Skettenis };
196432c5292Skettenis 
197432c5292Skettenis int
amlmmc_match(struct device * parent,void * match,void * aux)198432c5292Skettenis amlmmc_match(struct device *parent, void *match, void *aux)
199432c5292Skettenis {
200432c5292Skettenis 	struct fdt_attach_args *faa = aux;
201432c5292Skettenis 
202a55f8224Skettenis 	return (OF_is_compatible(faa->fa_node, "amlogic,meson-axg-mmc") ||
203a55f8224Skettenis 	    OF_is_compatible(faa->fa_node, "amlogic,meson-sm1-mmc"));
204432c5292Skettenis }
205432c5292Skettenis 
206432c5292Skettenis void
amlmmc_attach(struct device * parent,struct device * self,void * aux)207432c5292Skettenis amlmmc_attach(struct device *parent, struct device *self, void *aux)
208432c5292Skettenis {
209432c5292Skettenis 	struct amlmmc_softc *sc = (struct amlmmc_softc *)self;
210432c5292Skettenis 	struct fdt_attach_args *faa = aux;
211432c5292Skettenis 	struct sdmmcbus_attach_args saa;
212432c5292Skettenis 	uint32_t cfg, width;
213432c5292Skettenis 	int error;
214432c5292Skettenis 
215432c5292Skettenis 	if (faa->fa_nreg < 1) {
216432c5292Skettenis 		printf(": no registers\n");
217432c5292Skettenis 		return;
218432c5292Skettenis 	}
219432c5292Skettenis 
220432c5292Skettenis 	sc->sc_iot = faa->fa_iot;
221432c5292Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
222432c5292Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
223432c5292Skettenis 		printf(": can't map registers\n");
224432c5292Skettenis 		return;
225432c5292Skettenis 	}
226432c5292Skettenis 
227432c5292Skettenis 	sc->sc_dmat = faa->fa_dmat;
228432c5292Skettenis 	error = amlmmc_alloc_descriptors(sc);
229432c5292Skettenis 	if (error) {
230*4b1a56afSjsg 		printf(": can't allocate descriptors\n");
231432c5292Skettenis 		goto unmap;
232432c5292Skettenis 	}
233432c5292Skettenis 	error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, AMLMMC_NDESC,
234432c5292Skettenis 	    AMLMMC_MAXSEGSZ, 0, BUS_DMA_WAITOK|BUS_DMA_ALLOCNOW, &sc->sc_dmap);
235432c5292Skettenis 	if (error) {
236432c5292Skettenis 		printf(": can't create DMA map\n");
237432c5292Skettenis 		goto free;
238432c5292Skettenis 	}
239432c5292Skettenis 
24092556e92Skettenis 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
24192556e92Skettenis 	    amlmmc_intr, sc, sc->sc_dev.dv_xname);
24292556e92Skettenis 	if (sc->sc_ih == NULL) {
24392556e92Skettenis 		printf(": can't establish interrupt\n");
24492556e92Skettenis 		goto destroy;
24592556e92Skettenis 	}
24692556e92Skettenis 
247432c5292Skettenis 	sc->sc_node = faa->fa_node;
248432c5292Skettenis 	printf("\n");
249432c5292Skettenis 
250432c5292Skettenis 	pinctrl_byname(faa->fa_node, "default");
251432c5292Skettenis 
252432c5292Skettenis 	clock_enable_all(faa->fa_node);
253432c5292Skettenis 	reset_deassert_all(faa->fa_node);
254432c5292Skettenis 
255432c5292Skettenis 	sc->sc_clkin0 = clock_get_frequency(faa->fa_node, "clkin0");
256432c5292Skettenis 	sc->sc_clkin1 = clock_get_frequency(faa->fa_node, "clkin1");
257432c5292Skettenis 
258432c5292Skettenis 	OF_getpropintarray(faa->fa_node, "cd-gpios", sc->sc_gpio,
259432c5292Skettenis 	    sizeof(sc->sc_gpio));
260432c5292Skettenis 	if (sc->sc_gpio[0])
261432c5292Skettenis 		gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_INPUT);
262432c5292Skettenis 
26358aa5fe5Skettenis 	sc->sc_vmmc = OF_getpropint(sc->sc_node, "vmmc-supply", 0);
26458aa5fe5Skettenis 	sc->sc_vqmmc = OF_getpropint(sc->sc_node, "vqmmc-supply", 0);
26558aa5fe5Skettenis 	sc->sc_pwrseq = OF_getpropint(sc->sc_node, "mmc-pwrseq", 0);
26658aa5fe5Skettenis 
267ab6980d6Skettenis 	/* XXX Pretend we only support 3.3V for now. */
268ab6980d6Skettenis 	sc->sc_ocr = MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V;
269ab6980d6Skettenis 
270432c5292Skettenis 	/* Initialize timings and block size. */
271a7a39a0dSkettenis 	cfg = SD_EMMC_CFG_ERR_ABORT;
272432c5292Skettenis 	cfg |= SD_EMMC_CFG_RC_CC_16;
273432c5292Skettenis 	cfg |= SD_EMMC_CFG_RESP_TIMEOUT_256;
274432c5292Skettenis 	cfg |= SD_EMMC_CFG_BL_LEN_512;
275432c5292Skettenis 	HWRITE4(sc, SD_EMMC_CFG, cfg);
276432c5292Skettenis 
27792556e92Skettenis 	/* Clear status bits & enable interrupts. */
27892556e92Skettenis 	HWRITE4(sc, SD_EMMC_STATUS, SD_EMMC_STATUS_MASK);
27992556e92Skettenis 	HWRITE4(sc, SD_EMMC_IRQ_EN, SD_EMMC_IRQ_EN_MASK);
28092556e92Skettenis 
28158aa5fe5Skettenis 	/* Reset eMMC. */
28258aa5fe5Skettenis 	if (sc->sc_pwrseq)
28358aa5fe5Skettenis 		amlmmc_pwrseq_reset(sc->sc_pwrseq);
28458aa5fe5Skettenis 
285432c5292Skettenis 	memset(&saa, 0, sizeof(saa));
286432c5292Skettenis 	saa.saa_busname = "sdmmc";
287432c5292Skettenis 	saa.sct = &amlmmc_chip_functions;
288432c5292Skettenis 	saa.sch = sc;
289432c5292Skettenis 	saa.dmat = sc->sc_dmat;
290432c5292Skettenis 	saa.dmap = sc->sc_dmap;
291432c5292Skettenis 	saa.caps = SMC_CAPS_DMA;
292432c5292Skettenis 	saa.flags = SMF_STOP_AFTER_MULTIPLE;
293432c5292Skettenis 
294432c5292Skettenis 	if (OF_getproplen(sc->sc_node, "cap-mmc-highspeed") == 0)
295432c5292Skettenis 		saa.caps |= SMC_CAPS_MMC_HIGHSPEED;
296432c5292Skettenis 	if (OF_getproplen(sc->sc_node, "cap-sd-highspeed") == 0)
297432c5292Skettenis 		saa.caps |= SMC_CAPS_SD_HIGHSPEED;
29858aa5fe5Skettenis 	if (OF_getproplen(sc->sc_node, "mmc-ddr-1_8v") == 0)
29958aa5fe5Skettenis 		saa.caps |= SMC_CAPS_MMC_DDR52;
300a7a39a0dSkettenis 	if (OF_getproplen(sc->sc_node, "mmc-hs200-1_8v") == 0)
301a7a39a0dSkettenis 		saa.caps |= SMC_CAPS_MMC_HS200;
302ab6980d6Skettenis 	if (OF_getproplen(sc->sc_node, "sd-uhs-sdr50") == 0)
303ab6980d6Skettenis 		saa.caps |= SMC_CAPS_UHS_SDR50;
304ab6980d6Skettenis #ifdef notyet
305ab6980d6Skettenis 	if (OF_getproplen(sc->sc_node, "sd-uhs-sdr104") == 0)
306ab6980d6Skettenis 		saa.caps |= SMC_CAPS_UHS_SDR104;
307ab6980d6Skettenis #endif
308ab6980d6Skettenis 
309ab6980d6Skettenis 	if (saa.caps & SMC_CAPS_UHS_MASK)
310ab6980d6Skettenis 		sc->sc_ocr |= MMC_OCR_S18A;
311432c5292Skettenis 
312432c5292Skettenis 	width = OF_getpropint(faa->fa_node, "bus-width", 1);
313432c5292Skettenis 	if (width >= 8)
314432c5292Skettenis 		saa.caps |= SMC_CAPS_8BIT_MODE;
315432c5292Skettenis 	if (width >= 4)
316432c5292Skettenis 		saa.caps |= SMC_CAPS_4BIT_MODE;
317432c5292Skettenis 
318432c5292Skettenis 	sc->sc_sdmmc = config_found(self, &saa, NULL);
319432c5292Skettenis 	return;
320432c5292Skettenis 
32192556e92Skettenis destroy:
32292556e92Skettenis 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
323432c5292Skettenis free:
324432c5292Skettenis 	amlmmc_free_descriptors(sc);
325432c5292Skettenis unmap:
326432c5292Skettenis 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
327432c5292Skettenis }
328432c5292Skettenis 
329432c5292Skettenis int
amlmmc_alloc_descriptors(struct amlmmc_softc * sc)330432c5292Skettenis amlmmc_alloc_descriptors(struct amlmmc_softc *sc)
331432c5292Skettenis {
332432c5292Skettenis 	int error, rseg;
333432c5292Skettenis 
334432c5292Skettenis 	/* Allocate descriptor memory */
335432c5292Skettenis 	error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE,
336432c5292Skettenis 	    PAGE_SIZE, sc->sc_desc_segs, 1, &rseg,
337432c5292Skettenis 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
338432c5292Skettenis 	if (error)
339432c5292Skettenis 		return error;
340432c5292Skettenis 	error = bus_dmamem_map(sc->sc_dmat, sc->sc_desc_segs, rseg,
341432c5292Skettenis 	    PAGE_SIZE, &sc->sc_desc, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
342432c5292Skettenis 	if (error) {
343432c5292Skettenis 		bus_dmamem_free(sc->sc_dmat, sc->sc_desc_segs, rseg);
344432c5292Skettenis 		return error;
345432c5292Skettenis 	}
346432c5292Skettenis 	error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
347432c5292Skettenis 	    0, BUS_DMA_WAITOK, &sc->sc_desc_map);
348432c5292Skettenis 	if (error) {
349432c5292Skettenis 		bus_dmamem_unmap(sc->sc_dmat, sc->sc_desc, PAGE_SIZE);
350432c5292Skettenis 		bus_dmamem_free(sc->sc_dmat, sc->sc_desc_segs, rseg);
351432c5292Skettenis 		return error;
352432c5292Skettenis 	}
353432c5292Skettenis 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_desc_map,
354432c5292Skettenis 	    sc->sc_desc, PAGE_SIZE, NULL, BUS_DMA_WAITOK | BUS_DMA_WRITE);
355432c5292Skettenis 	if (error) {
356432c5292Skettenis 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_desc_map);
357432c5292Skettenis 		bus_dmamem_unmap(sc->sc_dmat, sc->sc_desc, PAGE_SIZE);
358432c5292Skettenis 		bus_dmamem_free(sc->sc_dmat, sc->sc_desc_segs, rseg);
359432c5292Skettenis 		return error;
360432c5292Skettenis 	}
361432c5292Skettenis 
362432c5292Skettenis 	sc->sc_desc_nsegs = rseg;
363432c5292Skettenis 	return 0;
364432c5292Skettenis }
365432c5292Skettenis 
366432c5292Skettenis void
amlmmc_free_descriptors(struct amlmmc_softc * sc)367432c5292Skettenis amlmmc_free_descriptors(struct amlmmc_softc *sc)
368432c5292Skettenis {
369432c5292Skettenis 	bus_dmamap_unload(sc->sc_dmat, sc->sc_desc_map);
370432c5292Skettenis 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_desc_map);
371432c5292Skettenis 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_desc, PAGE_SIZE);
372432c5292Skettenis 	bus_dmamem_free(sc->sc_dmat, sc->sc_desc_segs, sc->sc_desc_nsegs);
373432c5292Skettenis }
374432c5292Skettenis 
37592556e92Skettenis int
amlmmc_intr(void * arg)37692556e92Skettenis amlmmc_intr(void *arg)
37792556e92Skettenis {
37892556e92Skettenis 	struct amlmmc_softc *sc = arg;
37992556e92Skettenis 	uint32_t status;
38092556e92Skettenis 
38192556e92Skettenis 	status = HREAD4(sc, SD_EMMC_STATUS);
38292556e92Skettenis 	if ((status & SD_EMMC_STATUS_MASK) == 0)
38392556e92Skettenis 		return 0;
38492556e92Skettenis 
38592556e92Skettenis 	HWRITE4(sc, SD_EMMC_STATUS, status);
38692556e92Skettenis 	sc->sc_status = status & SD_EMMC_STATUS_MASK;
38792556e92Skettenis 	wakeup(sc);
38892556e92Skettenis 	return 1;
38992556e92Skettenis }
39092556e92Skettenis 
391432c5292Skettenis void
amlmmc_set_blklen(struct amlmmc_softc * sc,int blklen)392432c5292Skettenis amlmmc_set_blklen(struct amlmmc_softc *sc, int blklen)
393432c5292Skettenis {
394432c5292Skettenis 	uint32_t cfg;
395432c5292Skettenis 
396432c5292Skettenis 	if (blklen == sc->sc_blklen)
397432c5292Skettenis 		return;
398432c5292Skettenis 
399432c5292Skettenis 	cfg = HREAD4(sc, SD_EMMC_CFG);
400432c5292Skettenis 	cfg &= ~SD_EMMC_CFG_BL_LEN_MASK;
401432c5292Skettenis 	cfg |= (fls(blklen) - 1) << SD_EMMC_CFG_BL_LEN_SHIFT;
402432c5292Skettenis 	HWRITE4(sc, SD_EMMC_CFG, cfg);
403432c5292Skettenis 	sc->sc_blklen = blklen;
404432c5292Skettenis }
405432c5292Skettenis 
40658aa5fe5Skettenis void
amlmmc_pwrseq_reset(uint32_t phandle)40758aa5fe5Skettenis amlmmc_pwrseq_reset(uint32_t phandle)
40858aa5fe5Skettenis {
40958aa5fe5Skettenis 	uint32_t *gpios, *gpio;
41058aa5fe5Skettenis 	int node;
41158aa5fe5Skettenis 	int len;
41258aa5fe5Skettenis 
41358aa5fe5Skettenis 	node = OF_getnodebyphandle(phandle);
41458aa5fe5Skettenis 	if (node == 0)
41558aa5fe5Skettenis 		return;
41658aa5fe5Skettenis 
41758aa5fe5Skettenis 	if (!OF_is_compatible(node, "mmc-pwrseq-emmc"))
41858aa5fe5Skettenis 		return;
41958aa5fe5Skettenis 
42058aa5fe5Skettenis 	len = OF_getproplen(node, "reset-gpios");
42158aa5fe5Skettenis 	if (len <= 0)
42258aa5fe5Skettenis 		return;
42358aa5fe5Skettenis 
42458aa5fe5Skettenis 	gpios = malloc(len, M_TEMP, M_WAITOK);
42558aa5fe5Skettenis 	OF_getpropintarray(node, "reset-gpios", gpios, len);
42658aa5fe5Skettenis 
42758aa5fe5Skettenis 	gpio = gpios;
42858aa5fe5Skettenis 	while (gpio && gpio < gpios + (len / sizeof(uint32_t))) {
42958aa5fe5Skettenis 		gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT);
43058aa5fe5Skettenis 		gpio_controller_set_pin(gpio, 1);
43158aa5fe5Skettenis 		delay(1);
43258aa5fe5Skettenis 		gpio_controller_set_pin(gpio, 0);
43358aa5fe5Skettenis 		delay(200);
43458aa5fe5Skettenis 		gpio = gpio_controller_next_pin(gpio);
43558aa5fe5Skettenis 	}
43658aa5fe5Skettenis 
43758aa5fe5Skettenis 	free(gpios, M_TEMP, len);
43858aa5fe5Skettenis }
43958aa5fe5Skettenis 
440432c5292Skettenis int
amlmmc_host_reset(sdmmc_chipset_handle_t sch)441432c5292Skettenis amlmmc_host_reset(sdmmc_chipset_handle_t sch)
442432c5292Skettenis {
443432c5292Skettenis 	printf("%s\n", __func__);
444432c5292Skettenis 	return 0;
445432c5292Skettenis }
446432c5292Skettenis 
447432c5292Skettenis uint32_t
amlmmc_host_ocr(sdmmc_chipset_handle_t sch)448432c5292Skettenis amlmmc_host_ocr(sdmmc_chipset_handle_t sch)
449432c5292Skettenis {
450ab6980d6Skettenis 	struct amlmmc_softc *sc = sch;
451ab6980d6Skettenis 	return sc->sc_ocr;
452432c5292Skettenis }
453432c5292Skettenis 
454432c5292Skettenis int
amlmmc_host_maxblklen(sdmmc_chipset_handle_t sch)455432c5292Skettenis amlmmc_host_maxblklen(sdmmc_chipset_handle_t sch)
456432c5292Skettenis {
457432c5292Skettenis 	return 512;
458432c5292Skettenis }
459432c5292Skettenis 
460432c5292Skettenis int
amlmmc_card_detect(sdmmc_chipset_handle_t sch)461432c5292Skettenis amlmmc_card_detect(sdmmc_chipset_handle_t sch)
462432c5292Skettenis {
463432c5292Skettenis 	struct amlmmc_softc *sc = sch;
464432c5292Skettenis 
465432c5292Skettenis 	if (OF_getproplen(sc->sc_node, "non-removable") == 0)
466432c5292Skettenis 		return 1;
467432c5292Skettenis 
468432c5292Skettenis 	if (sc->sc_gpio[0]) {
469432c5292Skettenis 		int inverted, val;
470432c5292Skettenis 
471432c5292Skettenis 		val = gpio_controller_get_pin(sc->sc_gpio);
472432c5292Skettenis 
473432c5292Skettenis 		inverted = (OF_getproplen(sc->sc_node, "cd-inverted") == 0);
474432c5292Skettenis 		return inverted ? !val : val;
475432c5292Skettenis 	}
476432c5292Skettenis 
477432c5292Skettenis 	return 1;
478432c5292Skettenis }
479432c5292Skettenis 
480432c5292Skettenis int
amlmmc_bus_power(sdmmc_chipset_handle_t sch,uint32_t ocr)481432c5292Skettenis amlmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
482432c5292Skettenis {
48358aa5fe5Skettenis 	struct amlmmc_softc *sc = sch;
48458aa5fe5Skettenis 	uint32_t vdd = 0;
48558aa5fe5Skettenis 
48658aa5fe5Skettenis 	if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V))
48758aa5fe5Skettenis 		vdd = 3300000;
48858aa5fe5Skettenis 
48958aa5fe5Skettenis 	/* enable mmc power */
49058aa5fe5Skettenis 	if (sc->sc_vmmc && vdd > 0)
49158aa5fe5Skettenis 		regulator_enable(sc->sc_vmmc);
49258aa5fe5Skettenis 
49358aa5fe5Skettenis 	if (sc->sc_vqmmc && vdd > 0)
49458aa5fe5Skettenis 		regulator_enable(sc->sc_vqmmc);
49558aa5fe5Skettenis 
49658aa5fe5Skettenis 	delay(10000);
49758aa5fe5Skettenis 
49858aa5fe5Skettenis 	sc->sc_vdd = vdd;
499432c5292Skettenis 	return 0;
500432c5292Skettenis }
501432c5292Skettenis 
502432c5292Skettenis int
amlmmc_bus_clock(sdmmc_chipset_handle_t sch,int freq,int timing)503432c5292Skettenis amlmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing)
504432c5292Skettenis {
505432c5292Skettenis 	struct amlmmc_softc *sc = sch;
506432c5292Skettenis 	uint32_t div, clock;
507432c5292Skettenis 
508a7a39a0dSkettenis 	/* XXX The ODROID-N2 eMMC doesn't work properly above 150 MHz. */
509a7a39a0dSkettenis 	if (freq > 150000)
510a7a39a0dSkettenis 		freq = 150000;
511a7a39a0dSkettenis 
51258aa5fe5Skettenis 	pinctrl_byname(sc->sc_node, "clk-gate");
51358aa5fe5Skettenis 
514432c5292Skettenis 	if (freq == 0)
515432c5292Skettenis 		return 0;
516432c5292Skettenis 
517299b5045Skettenis 	/* Convert clock frequency from kHz to Hz. */
518432c5292Skettenis 	freq = freq * 1000;
519432c5292Skettenis 
52092525d31Skettenis 	/* Double the clock rate for DDR modes. */
52192525d31Skettenis 	if (timing == SDMMC_TIMING_MMC_DDR52)
52292525d31Skettenis 		freq = freq * 2;
52392525d31Skettenis 
524432c5292Skettenis 	if (freq < (sc->sc_clkin1 / SD_EMMC_CLOCK_DIV_MAX)) {
525432c5292Skettenis 		div = (sc->sc_clkin0 + freq - 1) / freq;
526432c5292Skettenis 		clock = SD_EMMC_CLOCK_CLK_SRC_24M | div;
527432c5292Skettenis 	} else {
528432c5292Skettenis 		div = (sc->sc_clkin1 + freq - 1) / freq;
529432c5292Skettenis 		clock = SD_EMMC_CLOCK_CLK_SRC_FCLK | div;
530432c5292Skettenis 	}
531432c5292Skettenis 	if (div > SD_EMMC_CLOCK_DIV_MAX)
532432c5292Skettenis 		return EINVAL;
533432c5292Skettenis 
53458aa5fe5Skettenis 	HSET4(sc, SD_EMMC_CFG, SD_EMMC_CFG_STOP_CLOCK);
53558aa5fe5Skettenis 
53658aa5fe5Skettenis 	if (timing == SDMMC_TIMING_MMC_DDR52)
53758aa5fe5Skettenis 		HSET4(sc, SD_EMMC_CFG, SD_EMMC_CFG_DDR);
53858aa5fe5Skettenis 	else
53958aa5fe5Skettenis 		HCLR4(sc, SD_EMMC_CFG, SD_EMMC_CFG_DDR);
54058aa5fe5Skettenis 
541a7a39a0dSkettenis 	clock |= SD_EMMC_CLOCK_ALWAYS_ON;
542432c5292Skettenis 	clock |= SD_EMMC_CLOCK_CO_PHASE_180;
54358aa5fe5Skettenis 	clock |= SD_EMMC_CLOCK_TX_PHASE_0;
544432c5292Skettenis 	clock |= SD_EMMC_CLOCK_RX_PHASE_0;
545432c5292Skettenis 	HWRITE4(sc, SD_EMMC_CLOCK, clock);
546432c5292Skettenis 
54758aa5fe5Skettenis 	HCLR4(sc, SD_EMMC_CFG, SD_EMMC_CFG_STOP_CLOCK);
54858aa5fe5Skettenis 
54958aa5fe5Skettenis 	pinctrl_byname(sc->sc_node, "default");
55058aa5fe5Skettenis 
551432c5292Skettenis 	return 0;
552432c5292Skettenis }
553432c5292Skettenis 
554432c5292Skettenis int
amlmmc_bus_width(sdmmc_chipset_handle_t sch,int width)555432c5292Skettenis amlmmc_bus_width(sdmmc_chipset_handle_t sch, int width)
556432c5292Skettenis {
557432c5292Skettenis 	struct amlmmc_softc *sc = sch;
558432c5292Skettenis 	uint32_t cfg;
559432c5292Skettenis 
560432c5292Skettenis 	cfg = HREAD4(sc, SD_EMMC_CFG);
561432c5292Skettenis 	cfg &= ~SD_EMMC_CFG_BUS_WIDTH_MASK;
562432c5292Skettenis 	switch (width) {
563432c5292Skettenis 	case 1:
564432c5292Skettenis 		cfg |= SD_EMMC_CFG_BUS_WIDTH_1;
565432c5292Skettenis 		break;
566432c5292Skettenis 	case 4:
567432c5292Skettenis 		cfg |= SD_EMMC_CFG_BUS_WIDTH_4;
568432c5292Skettenis 		break;
569432c5292Skettenis 	case 8:
570432c5292Skettenis 		cfg |= SD_EMMC_CFG_BUS_WIDTH_8;
571432c5292Skettenis 		break;
572432c5292Skettenis 	default:
573432c5292Skettenis 		return EINVAL;
574432c5292Skettenis 	}
575432c5292Skettenis 	HWRITE4(sc, SD_EMMC_CFG, cfg);
576432c5292Skettenis 
577432c5292Skettenis 	return 0;
578432c5292Skettenis }
579432c5292Skettenis 
580432c5292Skettenis void
amlmmc_exec_command(sdmmc_chipset_handle_t sch,struct sdmmc_command * cmd)581432c5292Skettenis amlmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
582432c5292Skettenis {
583432c5292Skettenis 	struct amlmmc_softc *sc = sch;
584432c5292Skettenis 	uint32_t cmd_cfg, status;
585432c5292Skettenis 	uint32_t data_addr = 0;
58692556e92Skettenis 	int s;
58792556e92Skettenis 
58892556e92Skettenis 	KASSERT(sc->sc_status == 0);
589432c5292Skettenis 
59045862b87Skettenis 	/* Setup descriptor flags. */
591432c5292Skettenis 	cmd_cfg = cmd->c_opcode << SD_EMMC_CMD_CFG_CMD_INDEX_SHIFT;
59245862b87Skettenis 	if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
593432c5292Skettenis 		cmd_cfg |= SD_EMMC_CMD_CFG_NO_RESP;
59445862b87Skettenis 	if (ISSET(cmd->c_flags, SCF_RSP_136))
595432c5292Skettenis 		cmd_cfg |= SD_EMMC_CMD_CFG_RESP_128;
59645862b87Skettenis 	if (ISSET(cmd->c_flags, SCF_RSP_BSY))
597432c5292Skettenis 		cmd_cfg |= SD_EMMC_CMD_CFG_R1B;
59845862b87Skettenis 	if (!ISSET(cmd->c_flags, SCF_RSP_CRC))
599432c5292Skettenis 		cmd_cfg |= SD_EMMC_CMD_CFG_RESP_NOCRC;
60045862b87Skettenis 	if (cmd->c_datalen > 0) {
60145862b87Skettenis 		cmd_cfg |= SD_EMMC_CMD_CFG_DATA_IO;
60245862b87Skettenis 		if (cmd->c_datalen >= cmd->c_blklen)
60345862b87Skettenis 			cmd_cfg |= SD_EMMC_CMD_CFG_BLOCK_MODE;
60445862b87Skettenis 		if (!ISSET(cmd->c_flags, SCF_CMD_READ))
60545862b87Skettenis 			cmd_cfg |= SD_EMMC_CMD_CFG_DATA_WR;
606432c5292Skettenis 		cmd_cfg |= SD_EMMC_CMD_CFG_TIMEOUT_4096;
60745862b87Skettenis 	} else {
608432c5292Skettenis 		cmd_cfg |= SD_EMMC_CMD_CFG_TIMEOUT_1024;
60945862b87Skettenis 	}
61045862b87Skettenis 	cmd_cfg |= SD_EMMC_CMD_CFG_OWNER;
611432c5292Skettenis 
61245862b87Skettenis 	/* If we have multiple DMA segments we need to use descriptors. */
61345862b87Skettenis 	if (cmd->c_datalen > 0 &&
61445862b87Skettenis 	    cmd->c_dmamap && cmd->c_dmamap->dm_nsegs > 1) {
61545862b87Skettenis 		struct amlmmc_desc *desc = (struct amlmmc_desc *)sc->sc_desc;
61645862b87Skettenis 		int seg;
61745862b87Skettenis 
61845862b87Skettenis 		for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
61945862b87Skettenis 			bus_addr_t addr = cmd->c_dmamap->dm_segs[seg].ds_addr;
62045862b87Skettenis 			bus_size_t len = cmd->c_dmamap->dm_segs[seg].ds_len;
62145862b87Skettenis 
62245862b87Skettenis 			if (seg == cmd->c_dmamap->dm_nsegs - 1)
62345862b87Skettenis 				cmd_cfg |= SD_EMMC_CMD_CFG_END_OF_CHAIN;
62445862b87Skettenis 
62545862b87Skettenis 			KASSERT((addr & 0x7) == 0);
62645862b87Skettenis 			desc[seg].cmd_cfg = cmd_cfg | (len / cmd->c_blklen);
62745862b87Skettenis 			desc[seg].cmd_arg = cmd->c_arg;
62845862b87Skettenis 			desc[seg].data_addr = addr;
62945862b87Skettenis 			desc[seg].resp_addr = 0;
63045862b87Skettenis 			cmd_cfg |= SD_EMMC_CMD_CFG_NO_CMD;
63145862b87Skettenis 		}
63245862b87Skettenis 
63345862b87Skettenis 		bus_dmamap_sync(sc->sc_dmat, sc->sc_desc_map, 0,
63445862b87Skettenis 		    cmd->c_dmamap->dm_nsegs * sizeof(struct amlmmc_desc),
63545862b87Skettenis 		    BUS_DMASYNC_PREWRITE);
63645862b87Skettenis 		HWRITE4(sc, SD_EMMC_START, SD_EMMC_START_START |
63745862b87Skettenis 		    sc->sc_desc_map->dm_segs[0].ds_addr);
63845862b87Skettenis 		goto wait;
63945862b87Skettenis 	}
64045862b87Skettenis 
64145862b87Skettenis 	/* Bounce if we don't have a DMA map. */
642432c5292Skettenis 	if (cmd->c_datalen > 0 && !cmd->c_dmamap) {
643432c5292Skettenis 		/* Abuse DMA descriptor memory as bounce buffer. */
644432c5292Skettenis 		KASSERT(cmd->c_datalen <= PAGE_SIZE);
645432c5292Skettenis 		if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
646432c5292Skettenis 			bus_dmamap_sync(sc->sc_dmat, sc->sc_desc_map, 0,
647432c5292Skettenis 			    cmd->c_datalen, BUS_DMASYNC_PREREAD);
648432c5292Skettenis 		} else {
649432c5292Skettenis 			memcpy(sc->sc_desc, cmd->c_data, cmd->c_datalen);
650432c5292Skettenis 			bus_dmamap_sync(sc->sc_dmat, sc->sc_desc_map, 0,
651432c5292Skettenis 			    cmd->c_datalen, BUS_DMASYNC_PREWRITE);
652432c5292Skettenis 		}
653432c5292Skettenis 	}
654432c5292Skettenis 
655432c5292Skettenis 	if (cmd->c_datalen > 0) {
656432c5292Skettenis 		if (cmd->c_datalen >= cmd->c_blklen) {
657432c5292Skettenis 			amlmmc_set_blklen(sc, cmd->c_blklen);
658432c5292Skettenis 			cmd_cfg |= cmd->c_datalen / cmd->c_blklen;
659432c5292Skettenis 		} else {
660432c5292Skettenis 			cmd_cfg |= cmd->c_datalen;
661432c5292Skettenis 		}
662432c5292Skettenis 
663432c5292Skettenis 		if (cmd->c_dmamap)
664432c5292Skettenis 			data_addr = cmd->c_dmamap->dm_segs[0].ds_addr;
665432c5292Skettenis 		else
666432c5292Skettenis 			data_addr = sc->sc_desc_map->dm_segs[0].ds_addr;
667432c5292Skettenis 	}
668432c5292Skettenis 
66945862b87Skettenis 	cmd_cfg |= SD_EMMC_CMD_CFG_END_OF_CHAIN;
67045862b87Skettenis 
67145862b87Skettenis 	KASSERT((data_addr & 0x7) == 0);
672432c5292Skettenis 	HWRITE4(sc, SD_EMMC_CMD_CFG, cmd_cfg);
673432c5292Skettenis 	HWRITE4(sc, SD_EMMC_CMD_DAT, data_addr);
674432c5292Skettenis 	HWRITE4(sc, SD_EMMC_CMD_RSP, 0);
675432c5292Skettenis 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, SD_EMMC_CMD_CFG,
676432c5292Skettenis 	    SD_EMMC_CMD_RSP1 - SD_EMMC_CMD_CFG, BUS_SPACE_BARRIER_WRITE);
677432c5292Skettenis 	HWRITE4(sc, SD_EMMC_CMD_ARG, cmd->c_arg);
678432c5292Skettenis 
67945862b87Skettenis wait:
68092556e92Skettenis 	s = splbio();
68192556e92Skettenis 	while (sc->sc_status == 0) {
68292556e92Skettenis 		if (tsleep_nsec(sc, PWAIT, "amlmmc", 10000000000))
683432c5292Skettenis 			break;
684432c5292Skettenis 	}
68592556e92Skettenis 	status = sc->sc_status;
68692556e92Skettenis 	sc->sc_status = 0;
68792556e92Skettenis 	splx(s);
68845862b87Skettenis 
68945862b87Skettenis 	if (!ISSET(status, SD_EMMC_STATUS_END_OF_CHAIN))
690432c5292Skettenis 		cmd->c_error = ETIMEDOUT;
69192556e92Skettenis 	else if (ISSET(status, SD_EMMC_STATUS_DESC_TIMEOUT))
69292556e92Skettenis 		cmd->c_error = ETIMEDOUT;
69345862b87Skettenis 	else if (ISSET(status, SD_EMMC_STATUS_RESP_TIMEOUT))
694432c5292Skettenis 		cmd->c_error = ETIMEDOUT;
69545862b87Skettenis 	else if (ISSET(status, SD_EMMC_STATUS_ERR_MASK))
696432c5292Skettenis 		cmd->c_error = EIO;
697432c5292Skettenis 
69845862b87Skettenis 	if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
69945862b87Skettenis 		if (ISSET(cmd->c_flags, SCF_RSP_136)) {
700432c5292Skettenis 			cmd->c_resp[0] = HREAD4(sc, SD_EMMC_CMD_RSP);
701432c5292Skettenis 			cmd->c_resp[1] = HREAD4(sc, SD_EMMC_CMD_RSP1);
702432c5292Skettenis 			cmd->c_resp[2] = HREAD4(sc, SD_EMMC_CMD_RSP2);
703432c5292Skettenis 			cmd->c_resp[3] = HREAD4(sc, SD_EMMC_CMD_RSP3);
70445862b87Skettenis 			if (ISSET(cmd->c_flags, SCF_RSP_CRC)) {
705432c5292Skettenis 				cmd->c_resp[0] = (cmd->c_resp[0] >> 8) |
706432c5292Skettenis 				    (cmd->c_resp[1] << 24);
707432c5292Skettenis 				cmd->c_resp[1] = (cmd->c_resp[1] >> 8) |
708432c5292Skettenis 				    (cmd->c_resp[2] << 24);
709432c5292Skettenis 				cmd->c_resp[2] = (cmd->c_resp[2] >> 8) |
710432c5292Skettenis 				    (cmd->c_resp[3] << 24);
711432c5292Skettenis 				cmd->c_resp[3] = (cmd->c_resp[3] >> 8);
712432c5292Skettenis 			}
713432c5292Skettenis 		} else {
714432c5292Skettenis 			cmd->c_resp[0] = HREAD4(sc, SD_EMMC_CMD_RSP);
715432c5292Skettenis 		}
716432c5292Skettenis 	}
717432c5292Skettenis 
71845862b87Skettenis 	/* Unbounce if we don't have a DMA map. */
719432c5292Skettenis 	if (cmd->c_datalen > 0 && !cmd->c_dmamap) {
720432c5292Skettenis 		if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
721432c5292Skettenis 			bus_dmamap_sync(sc->sc_dmat, sc->sc_desc_map, 0,
722432c5292Skettenis 			    cmd->c_datalen, BUS_DMASYNC_POSTREAD);
723432c5292Skettenis 			memcpy(cmd->c_data, sc->sc_desc, cmd->c_datalen);
724432c5292Skettenis 		} else {
725432c5292Skettenis 			bus_dmamap_sync(sc->sc_dmat, sc->sc_desc_map, 0,
726432c5292Skettenis 			    cmd->c_datalen, BUS_DMASYNC_POSTWRITE);
727432c5292Skettenis 		}
728432c5292Skettenis 	}
729432c5292Skettenis 
73045862b87Skettenis 	/* Cleanup descriptors. */
73145862b87Skettenis 	if (cmd->c_datalen > 0 &&
73245862b87Skettenis 	    cmd->c_dmamap && cmd->c_dmamap->dm_nsegs > 1) {
73345862b87Skettenis 		HWRITE4(sc, SD_EMMC_START, SD_EMMC_START_STOP);
73445862b87Skettenis 		bus_dmamap_sync(sc->sc_dmat, sc->sc_desc_map, 0,
73545862b87Skettenis 		    cmd->c_dmamap->dm_nsegs * sizeof(struct amlmmc_desc),
73645862b87Skettenis 		    BUS_DMASYNC_POSTWRITE);
73745862b87Skettenis 	}
73845862b87Skettenis 
73945862b87Skettenis 	SET(cmd->c_flags, SCF_ITSDONE);
740432c5292Skettenis }
74158aa5fe5Skettenis 
74258aa5fe5Skettenis int
amlmmc_signal_voltage(sdmmc_chipset_handle_t sch,int signal_voltage)74358aa5fe5Skettenis amlmmc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage)
74458aa5fe5Skettenis {
74551e951d2Skettenis 	struct amlmmc_softc *sc = sch;
74651e951d2Skettenis 	uint32_t vccq;
74751e951d2Skettenis 
74851e951d2Skettenis 	if (sc->sc_vqmmc == 0)
74951e951d2Skettenis 		return ENODEV;
75051e951d2Skettenis 
75151e951d2Skettenis 	switch (signal_voltage) {
75251e951d2Skettenis 	case SDMMC_SIGNAL_VOLTAGE_180:
75351e951d2Skettenis 		vccq = 1800000;
75451e951d2Skettenis 		break;
75551e951d2Skettenis 	case SDMMC_SIGNAL_VOLTAGE_330:
75651e951d2Skettenis 		vccq = 3300000;
75751e951d2Skettenis 		break;
75851e951d2Skettenis 	default:
75951e951d2Skettenis 		return EINVAL;
76051e951d2Skettenis 	}
76151e951d2Skettenis 
76251e951d2Skettenis 	if (regulator_get_voltage(sc->sc_vqmmc) == vccq)
76358aa5fe5Skettenis 		return 0;
76451e951d2Skettenis 
76551e951d2Skettenis 	return regulator_set_voltage(sc->sc_vqmmc, vccq);
76658aa5fe5Skettenis }
767a7a39a0dSkettenis 
768a7a39a0dSkettenis int
amlmmc_execute_tuning(sdmmc_chipset_handle_t sch,int timing)769a7a39a0dSkettenis amlmmc_execute_tuning(sdmmc_chipset_handle_t sch, int timing)
770a7a39a0dSkettenis {
771a7a39a0dSkettenis 	struct amlmmc_softc *sc = sch;
772a7a39a0dSkettenis 	struct sdmmc_command cmd;
773a7a39a0dSkettenis 	uint32_t adjust, cfg, div;
774a7a39a0dSkettenis 	int opcode, delay;
775a7a39a0dSkettenis 	char data[128];
776a7a39a0dSkettenis 
777a7a39a0dSkettenis 	switch (timing) {
778a7a39a0dSkettenis 	case SDMMC_TIMING_MMC_HS200:
779a7a39a0dSkettenis 		opcode = MMC_SEND_TUNING_BLOCK_HS200;
780a7a39a0dSkettenis 		break;
781a7a39a0dSkettenis 	case SDMMC_TIMING_UHS_SDR50:
782a7a39a0dSkettenis 	case SDMMC_TIMING_UHS_SDR104:
783a7a39a0dSkettenis 		opcode = MMC_SEND_TUNING_BLOCK;
784a7a39a0dSkettenis 		break;
785a7a39a0dSkettenis 	default:
786a7a39a0dSkettenis 		return EINVAL;
787a7a39a0dSkettenis 	}
788a7a39a0dSkettenis 
789a7a39a0dSkettenis 	cfg = HREAD4(sc, SD_EMMC_CFG);
790a7a39a0dSkettenis 	div = HREAD4(sc, SD_EMMC_CLOCK) & SD_EMMC_CLOCK_DIV_MAX;
791a7a39a0dSkettenis 
792a7a39a0dSkettenis 	adjust = HREAD4(sc, SD_EMMC_ADJUST);
793a7a39a0dSkettenis 	adjust |= SD_EMMC_ADJUST_ADJ_FIXED;
794a7a39a0dSkettenis 	HWRITE4(sc, SD_EMMC_ADJUST, adjust);
795a7a39a0dSkettenis 
796a7a39a0dSkettenis 	for (delay = 0; delay < div; delay++) {
797a7a39a0dSkettenis 		adjust &= ~SD_EMMC_ADJUST_ADJ_DELAY_MASK;
798a7a39a0dSkettenis 		adjust |= (delay << SD_EMMC_ADJUST_ADJ_DELAY_SHIFT);
799a7a39a0dSkettenis 		HWRITE4(sc, SD_EMMC_ADJUST, adjust);
800a7a39a0dSkettenis 
801a7a39a0dSkettenis 		memset(&cmd, 0, sizeof(cmd));
802a7a39a0dSkettenis 		cmd.c_opcode = opcode;
803a7a39a0dSkettenis 		cmd.c_arg = 0;
804a7a39a0dSkettenis 		cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
805a7a39a0dSkettenis 		if (cfg & SD_EMMC_CFG_BUS_WIDTH_8) {
806a7a39a0dSkettenis 			cmd.c_blklen = cmd.c_datalen = 128;
807a7a39a0dSkettenis 		} else {
808a7a39a0dSkettenis 			cmd.c_blklen = cmd.c_datalen = 64;
809a7a39a0dSkettenis 		}
810a7a39a0dSkettenis 		cmd.c_data = data;
811a7a39a0dSkettenis 
812a7a39a0dSkettenis 		amlmmc_exec_command(sch, &cmd);
813a7a39a0dSkettenis 		if (cmd.c_error == 0)
814a7a39a0dSkettenis 			return 0;
815a7a39a0dSkettenis 	}
816a7a39a0dSkettenis 
817a7a39a0dSkettenis 	adjust = HREAD4(sc, SD_EMMC_ADJUST);
818a7a39a0dSkettenis 	adjust &= ~SD_EMMC_ADJUST_ADJ_FIXED;
819a7a39a0dSkettenis 	HWRITE4(sc, SD_EMMC_ADJUST, adjust);
820a7a39a0dSkettenis 
821a7a39a0dSkettenis 	return EIO;
822a7a39a0dSkettenis }
823