xref: /dflybsd-src/sys/dev/disk/sdhci/sdhci_pci.c (revision 502d982c7d2fa8a5f352ab7ee72e877d7b541538)
1e355a444SMarkus Pfeiffer /*-
2e355a444SMarkus Pfeiffer  * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
3e355a444SMarkus Pfeiffer  * All rights reserved.
4e355a444SMarkus Pfeiffer  *
5e355a444SMarkus Pfeiffer  * Redistribution and use in source and binary forms, with or without
6e355a444SMarkus Pfeiffer  * modification, are permitted provided that the following conditions
7e355a444SMarkus Pfeiffer  * are met:
8e355a444SMarkus Pfeiffer  * 1. Redistributions of source code must retain the above copyright
9e355a444SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer.
10e355a444SMarkus Pfeiffer  * 2. Redistributions in binary form must reproduce the above copyright
11e355a444SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer in the
12e355a444SMarkus Pfeiffer  *    documentation and/or other materials provided with the distribution.
13e355a444SMarkus Pfeiffer  *
14e355a444SMarkus Pfeiffer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15e355a444SMarkus Pfeiffer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16e355a444SMarkus Pfeiffer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17e355a444SMarkus Pfeiffer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18e355a444SMarkus Pfeiffer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19e355a444SMarkus Pfeiffer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20e355a444SMarkus Pfeiffer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21e355a444SMarkus Pfeiffer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22e355a444SMarkus Pfeiffer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23e355a444SMarkus Pfeiffer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24e355a444SMarkus Pfeiffer  */
25e355a444SMarkus Pfeiffer 
26e355a444SMarkus Pfeiffer #include <sys/param.h>
27e355a444SMarkus Pfeiffer #include <sys/systm.h>
28e355a444SMarkus Pfeiffer #include <sys/bus.h>
29e355a444SMarkus Pfeiffer #include <sys/kernel.h>
30e355a444SMarkus Pfeiffer #include <sys/lock.h>
31e355a444SMarkus Pfeiffer #include <sys/module.h>
32e355a444SMarkus Pfeiffer #include <sys/resource.h>
33e355a444SMarkus Pfeiffer #include <sys/rman.h>
34e355a444SMarkus Pfeiffer #include <sys/sysctl.h>
35e355a444SMarkus Pfeiffer #include <sys/taskqueue.h>
36e355a444SMarkus Pfeiffer 
37e355a444SMarkus Pfeiffer #include <bus/pci/pcireg.h>
38e355a444SMarkus Pfeiffer #include <bus/pci/pcivar.h>
39e355a444SMarkus Pfeiffer 
40e355a444SMarkus Pfeiffer #include <bus/mmc/bridge.h>
41e355a444SMarkus Pfeiffer 
424d3ae590SImre Vadász #include <dev/disk/sdhci/sdhci.h>
434d3ae590SImre Vadász 
44e355a444SMarkus Pfeiffer #include "mmcbr_if.h"
45e355a444SMarkus Pfeiffer #include "sdhci_if.h"
46e355a444SMarkus Pfeiffer 
47e355a444SMarkus Pfeiffer /*
48e355a444SMarkus Pfeiffer  * PCI registers
49e355a444SMarkus Pfeiffer  */
50e355a444SMarkus Pfeiffer #define PCI_SDHCI_IFPIO			0x00
51e355a444SMarkus Pfeiffer #define PCI_SDHCI_IFDMA			0x01
52e355a444SMarkus Pfeiffer #define PCI_SDHCI_IFVENDOR		0x02
53e355a444SMarkus Pfeiffer 
54e355a444SMarkus Pfeiffer #define PCI_SLOT_INFO			0x40	/* 8 bits */
55e355a444SMarkus Pfeiffer #define  PCI_SLOT_INFO_SLOTS(x)		(((x >> 4) & 7) + 1)
56e355a444SMarkus Pfeiffer #define  PCI_SLOT_INFO_FIRST_BAR(x)	((x) & 7)
57e355a444SMarkus Pfeiffer 
58e355a444SMarkus Pfeiffer /*
59e355a444SMarkus Pfeiffer  * RICOH specific PCI registers
60e355a444SMarkus Pfeiffer  */
61e355a444SMarkus Pfeiffer #define	SDHC_PCI_MODE_KEY		0xf9
62e355a444SMarkus Pfeiffer #define	SDHC_PCI_MODE			0x150
63e355a444SMarkus Pfeiffer #define	SDHC_PCI_MODE_SD20		0x10
64e355a444SMarkus Pfeiffer #define	SDHC_PCI_BASE_FREQ_KEY		0xfc
65e355a444SMarkus Pfeiffer #define	SDHC_PCI_BASE_FREQ		0xe1
66e355a444SMarkus Pfeiffer 
67e355a444SMarkus Pfeiffer static const struct sdhci_device {
68e355a444SMarkus Pfeiffer 	uint32_t	model;
69e355a444SMarkus Pfeiffer 	uint16_t	subvendor;
70e355a444SMarkus Pfeiffer 	const char	*desc;
71e355a444SMarkus Pfeiffer 	u_int		quirks;
72e355a444SMarkus Pfeiffer } sdhci_devices[] = {
73e355a444SMarkus Pfeiffer 	{ 0x08221180, 	0xffff,	"RICOH R5C822 SD",
7422caf486SImre Vadász 	    SDHCI_QUIRK_FORCE_SDMA },
754f29f02bSImre Vadász 	{ 0xe8221180, 	0xffff,	"RICOH R5CE822 SD",
7622caf486SImre Vadász 	    SDHCI_QUIRK_FORCE_SDMA |
774f29f02bSImre Vadász 	    SDHCI_QUIRK_LOWER_FREQUENCY },
78e355a444SMarkus Pfeiffer 	{ 0xe8231180, 	0xffff,	"RICOH R5CE823 SD",
79e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_LOWER_FREQUENCY },
80e355a444SMarkus Pfeiffer 	{ 0x8034104c, 	0xffff, "TI XX21/XX11 SD",
8122caf486SImre Vadász 	    SDHCI_QUIRK_FORCE_SDMA },
82e355a444SMarkus Pfeiffer 	{ 0x05501524, 	0xffff, "ENE CB712 SD",
83e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_BROKEN_TIMINGS },
84e355a444SMarkus Pfeiffer 	{ 0x05511524, 	0xffff, "ENE CB712 SD 2",
85e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_BROKEN_TIMINGS },
86e355a444SMarkus Pfeiffer 	{ 0x07501524, 	0xffff, "ENE CB714 SD",
87e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_RESET_ON_IOS |
88e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_BROKEN_TIMINGS },
89e355a444SMarkus Pfeiffer 	{ 0x07511524, 	0xffff, "ENE CB714 SD 2",
90e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_RESET_ON_IOS |
91e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_BROKEN_TIMINGS },
92e355a444SMarkus Pfeiffer 	{ 0x410111ab, 	0xffff, "Marvell CaFe SD",
93e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_INCR_TIMEOUT_CONTROL },
94e355a444SMarkus Pfeiffer 	{ 0x2381197B, 	0xffff,	"JMicron JMB38X SD",
95e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_32BIT_DMA_SIZE |
96e355a444SMarkus Pfeiffer 	    SDHCI_QUIRK_RESET_AFTER_REQUEST },
974f29f02bSImre Vadász 	{ 0x16bc14e4,	0xffff,	"Broadcom BCM577xx SDXC/MMC Card Reader",
984f29f02bSImre Vadász 	    SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC },
9985ccd313SImre Vadász 	{ 0x0f148086,	0xffff, "Intel Bay Trail eMMC 4.5 Controller",
10085ccd313SImre Vadász 	    SDHCI_QUIRK_WHITELIST_ADMA2 |
101*7ba10b88SImre Vadász 	    SDHCI_QUIRK_WAIT_WHILE_BUSY |
102*7ba10b88SImre Vadász 	    SDHCI_QUIRK_MMC_DDR52 |
103*7ba10b88SImre Vadász 	    SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
104*7ba10b88SImre Vadász 	    SDHCI_QUIRK_PRESET_VALUE_BROKEN},
10585ccd313SImre Vadász 	{ 0x0f158086,	0xffff, "Intel Bay Trail SDXC Controller",
10685ccd313SImre Vadász 	    SDHCI_QUIRK_WHITELIST_ADMA2 |
107*7ba10b88SImre Vadász 	    SDHCI_QUIRK_WAIT_WHILE_BUSY |
108*7ba10b88SImre Vadász 	    SDHCI_QUIRK_PRESET_VALUE_BROKEN },
10985ccd313SImre Vadász 	{ 0x0f508086,	0xffff, "Intel Bay Trail eMMC 4.5 Controller",
11085ccd313SImre Vadász 	    SDHCI_QUIRK_WHITELIST_ADMA2 |
111*7ba10b88SImre Vadász 	    SDHCI_QUIRK_WAIT_WHILE_BUSY |
112*7ba10b88SImre Vadász 	    SDHCI_QUIRK_MMC_DDR52 |
113*7ba10b88SImre Vadász 	    SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
114*7ba10b88SImre Vadász 	    SDHCI_QUIRK_PRESET_VALUE_BROKEN },
11585ccd313SImre Vadász 	{ 0x22948086,	0xffff, "Intel Braswell eMMC 4.5.1 Controller",
11685ccd313SImre Vadász 	    SDHCI_QUIRK_WHITELIST_ADMA2 |
117*7ba10b88SImre Vadász 	    SDHCI_QUIRK_WAIT_WHILE_BUSY |
118*7ba10b88SImre Vadász 	    SDHCI_QUIRK_MMC_DDR52 |
119*7ba10b88SImre Vadász 	    SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
120*7ba10b88SImre Vadász 	    SDHCI_QUIRK_PRESET_VALUE_BROKEN },
12185ccd313SImre Vadász 	{ 0x22968086,	0xffff, "Intel Braswell SDXC Controller",
12285ccd313SImre Vadász 	    SDHCI_QUIRK_WHITELIST_ADMA2 |
123*7ba10b88SImre Vadász 	    SDHCI_QUIRK_WAIT_WHILE_BUSY |
124*7ba10b88SImre Vadász 	    SDHCI_QUIRK_PRESET_VALUE_BROKEN },
12585ccd313SImre Vadász 	{ 0x5aca8086,	0xffff, "Intel Apollo Lake SDXC Controller",
12685ccd313SImre Vadász 	    SDHCI_QUIRK_BROKEN_DMA |	/* APL18 erratum */
127*7ba10b88SImre Vadász 	    SDHCI_QUIRK_WAIT_WHILE_BUSY |
128*7ba10b88SImre Vadász 	    SDHCI_QUIRK_PRESET_VALUE_BROKEN },
12985ccd313SImre Vadász 	{ 0x5acc8086,	0xffff, "Intel Apollo Lake eMMC 5.0 Controller",
13085ccd313SImre Vadász 	    SDHCI_QUIRK_BROKEN_DMA |	/* APL18 erratum */
131*7ba10b88SImre Vadász 	    SDHCI_QUIRK_WAIT_WHILE_BUSY |
132*7ba10b88SImre Vadász 	    SDHCI_QUIRK_MMC_DDR52 |
133*7ba10b88SImre Vadász 	    SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 |
134*7ba10b88SImre Vadász 	    SDHCI_QUIRK_PRESET_VALUE_BROKEN },
135e355a444SMarkus Pfeiffer 	{ 0,		0xffff,	NULL,
136e355a444SMarkus Pfeiffer 	    0 }
137e355a444SMarkus Pfeiffer };
138e355a444SMarkus Pfeiffer 
139e355a444SMarkus Pfeiffer struct sdhci_pci_softc {
140e355a444SMarkus Pfeiffer 	u_int		quirks;		/* Chip specific quirks */
141e355a444SMarkus Pfeiffer 	struct resource *irq_res;	/* IRQ resource */
142e355a444SMarkus Pfeiffer 	void 		*intrhand;	/* Interrupt handle */
143e355a444SMarkus Pfeiffer 
144e355a444SMarkus Pfeiffer 	int		num_slots;	/* Number of slots on this controller */
145e355a444SMarkus Pfeiffer 	struct sdhci_slot slots[6];
146e355a444SMarkus Pfeiffer 	struct resource	*mem_res[6];	/* Memory resource */
1474f29f02bSImre Vadász 	uint8_t		cfg_freq;	/* Saved mode */
1484f29f02bSImre Vadász 	uint8_t		cfg_mode;	/* Saved frequency */
149e355a444SMarkus Pfeiffer };
150e355a444SMarkus Pfeiffer 
151e355a444SMarkus Pfeiffer static int sdhci_enable_msi = 1;
152e355a444SMarkus Pfeiffer TUNABLE_INT("hw.sdhci_enable_msi", &sdhci_enable_msi);
153e355a444SMarkus Pfeiffer 
154e355a444SMarkus Pfeiffer static uint8_t
sdhci_pci_read_1(device_t dev,struct sdhci_slot * slot __unused,bus_size_t off)15570a02aadSImre Vadász sdhci_pci_read_1(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off)
156e355a444SMarkus Pfeiffer {
157e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
158e355a444SMarkus Pfeiffer 
159e355a444SMarkus Pfeiffer 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
160e355a444SMarkus Pfeiffer 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
161e355a444SMarkus Pfeiffer 	return bus_read_1(sc->mem_res[slot->num], off);
162e355a444SMarkus Pfeiffer }
163e355a444SMarkus Pfeiffer 
164e355a444SMarkus Pfeiffer static void
sdhci_pci_write_1(device_t dev,struct sdhci_slot * slot __unused,bus_size_t off,uint8_t val)16570a02aadSImre Vadász sdhci_pci_write_1(device_t dev, struct sdhci_slot *slot __unused,
16670a02aadSImre Vadász     bus_size_t off, uint8_t val)
167e355a444SMarkus Pfeiffer {
168e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
169e355a444SMarkus Pfeiffer 
170e355a444SMarkus Pfeiffer 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
171e355a444SMarkus Pfeiffer 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
172e355a444SMarkus Pfeiffer 	bus_write_1(sc->mem_res[slot->num], off, val);
173e355a444SMarkus Pfeiffer }
174e355a444SMarkus Pfeiffer 
175e355a444SMarkus Pfeiffer static uint16_t
sdhci_pci_read_2(device_t dev,struct sdhci_slot * slot __unused,bus_size_t off)17670a02aadSImre Vadász sdhci_pci_read_2(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off)
177e355a444SMarkus Pfeiffer {
178e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
179e355a444SMarkus Pfeiffer 
180e355a444SMarkus Pfeiffer 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
181e355a444SMarkus Pfeiffer 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
182e355a444SMarkus Pfeiffer 	return bus_read_2(sc->mem_res[slot->num], off);
183e355a444SMarkus Pfeiffer }
184e355a444SMarkus Pfeiffer 
185e355a444SMarkus Pfeiffer static void
sdhci_pci_write_2(device_t dev,struct sdhci_slot * slot __unused,bus_size_t off,uint16_t val)18670a02aadSImre Vadász sdhci_pci_write_2(device_t dev, struct sdhci_slot *slot __unused,
18770a02aadSImre Vadász     bus_size_t off, uint16_t val)
188e355a444SMarkus Pfeiffer {
189e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
190e355a444SMarkus Pfeiffer 
191e355a444SMarkus Pfeiffer 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
192e355a444SMarkus Pfeiffer 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
193e355a444SMarkus Pfeiffer 	bus_write_2(sc->mem_res[slot->num], off, val);
194e355a444SMarkus Pfeiffer }
195e355a444SMarkus Pfeiffer 
196e355a444SMarkus Pfeiffer static uint32_t
sdhci_pci_read_4(device_t dev,struct sdhci_slot * slot __unused,bus_size_t off)19770a02aadSImre Vadász sdhci_pci_read_4(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off)
198e355a444SMarkus Pfeiffer {
199e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
200e355a444SMarkus Pfeiffer 
201e355a444SMarkus Pfeiffer 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
202e355a444SMarkus Pfeiffer 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
203e355a444SMarkus Pfeiffer 	return bus_read_4(sc->mem_res[slot->num], off);
204e355a444SMarkus Pfeiffer }
205e355a444SMarkus Pfeiffer 
206e355a444SMarkus Pfeiffer static void
sdhci_pci_write_4(device_t dev,struct sdhci_slot * slot __unused,bus_size_t off,uint32_t val)20770a02aadSImre Vadász sdhci_pci_write_4(device_t dev, struct sdhci_slot *slot __unused,
20870a02aadSImre Vadász     bus_size_t off, uint32_t val)
209e355a444SMarkus Pfeiffer {
210e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
211e355a444SMarkus Pfeiffer 
212e355a444SMarkus Pfeiffer 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
213e355a444SMarkus Pfeiffer 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
214e355a444SMarkus Pfeiffer 	bus_write_4(sc->mem_res[slot->num], off, val);
215e355a444SMarkus Pfeiffer }
216e355a444SMarkus Pfeiffer 
217e355a444SMarkus Pfeiffer static void
sdhci_pci_read_multi_4(device_t dev,struct sdhci_slot * slot __unused,bus_size_t off,uint32_t * data,bus_size_t count)21870a02aadSImre Vadász sdhci_pci_read_multi_4(device_t dev, struct sdhci_slot *slot __unused,
219e355a444SMarkus Pfeiffer     bus_size_t off, uint32_t *data, bus_size_t count)
220e355a444SMarkus Pfeiffer {
221e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
222e355a444SMarkus Pfeiffer 
223e355a444SMarkus Pfeiffer 	bus_read_multi_stream_4(sc->mem_res[slot->num], off, data, count);
224e355a444SMarkus Pfeiffer }
225e355a444SMarkus Pfeiffer 
226e355a444SMarkus Pfeiffer static void
sdhci_pci_write_multi_4(device_t dev,struct sdhci_slot * slot __unused,bus_size_t off,uint32_t * data,bus_size_t count)22770a02aadSImre Vadász sdhci_pci_write_multi_4(device_t dev, struct sdhci_slot *slot __unused,
228e355a444SMarkus Pfeiffer     bus_size_t off, uint32_t *data, bus_size_t count)
229e355a444SMarkus Pfeiffer {
230e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
231e355a444SMarkus Pfeiffer 
232e355a444SMarkus Pfeiffer 	bus_write_multi_stream_4(sc->mem_res[slot->num], off, data, count);
233e355a444SMarkus Pfeiffer }
234e355a444SMarkus Pfeiffer 
235e355a444SMarkus Pfeiffer static void sdhci_pci_intr(void *arg);
236e355a444SMarkus Pfeiffer 
237e355a444SMarkus Pfeiffer static void
sdhci_lower_frequency(device_t dev)238e355a444SMarkus Pfeiffer sdhci_lower_frequency(device_t dev)
239e355a444SMarkus Pfeiffer {
2404f29f02bSImre Vadász 	struct sdhci_pci_softc *sc = device_get_softc(dev);
241e355a444SMarkus Pfeiffer 
2424f29f02bSImre Vadász 	/*
2434f29f02bSImre Vadász 	 * Enable SD2.0 mode.
2444f29f02bSImre Vadász 	 * NB: for RICOH R5CE823, this changes the PCI device ID to 0xe822.
2454f29f02bSImre Vadász 	 */
246e355a444SMarkus Pfeiffer 	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0xfc, 1);
2474f29f02bSImre Vadász 	sc->cfg_mode = pci_read_config(dev, SDHC_PCI_MODE, 1);
248e355a444SMarkus Pfeiffer 	pci_write_config(dev, SDHC_PCI_MODE, SDHC_PCI_MODE_SD20, 1);
249e355a444SMarkus Pfeiffer 	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0x00, 1);
250e355a444SMarkus Pfeiffer 
251e355a444SMarkus Pfeiffer 	/*
252e355a444SMarkus Pfeiffer 	 * Some SD/MMC cards don't work with the default base
2534f29f02bSImre Vadász 	 * clock frequency of 200 MHz.  Lower it to 50 MHz.
254e355a444SMarkus Pfeiffer 	 */
255e355a444SMarkus Pfeiffer 	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x01, 1);
2564f29f02bSImre Vadász 	sc->cfg_freq = pci_read_config(dev, SDHC_PCI_BASE_FREQ, 1);
257e355a444SMarkus Pfeiffer 	pci_write_config(dev, SDHC_PCI_BASE_FREQ, 50, 1);
258e355a444SMarkus Pfeiffer 	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x00, 1);
259e355a444SMarkus Pfeiffer }
260e355a444SMarkus Pfeiffer 
2614f29f02bSImre Vadász static void
sdhci_restore_frequency(device_t dev)2624f29f02bSImre Vadász sdhci_restore_frequency(device_t dev)
2634f29f02bSImre Vadász {
2644f29f02bSImre Vadász 	struct sdhci_pci_softc *sc = device_get_softc(dev);
2654f29f02bSImre Vadász 
2664f29f02bSImre Vadász 	/* Restore mode. */
2674f29f02bSImre Vadász 	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0xfc, 1);
2684f29f02bSImre Vadász 	pci_write_config(dev, SDHC_PCI_MODE, sc->cfg_mode, 1);
2694f29f02bSImre Vadász 	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0x00, 1);
2704f29f02bSImre Vadász 
2714f29f02bSImre Vadász 	/* Restore frequency. */
2724f29f02bSImre Vadász 	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x01, 1);
2734f29f02bSImre Vadász 	pci_write_config(dev, SDHC_PCI_BASE_FREQ, sc->cfg_freq, 1);
2744f29f02bSImre Vadász 	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x00, 1);
2754f29f02bSImre Vadász }
2764f29f02bSImre Vadász 
277e355a444SMarkus Pfeiffer static int
sdhci_pci_probe(device_t dev)278e355a444SMarkus Pfeiffer sdhci_pci_probe(device_t dev)
279e355a444SMarkus Pfeiffer {
280e355a444SMarkus Pfeiffer 	uint32_t model;
281e355a444SMarkus Pfeiffer 	uint16_t subvendor;
282e355a444SMarkus Pfeiffer 	uint8_t class, subclass;
283e355a444SMarkus Pfeiffer 	int i, result;
284e355a444SMarkus Pfeiffer 
285e355a444SMarkus Pfeiffer 	model = (uint32_t)pci_get_device(dev) << 16;
286e355a444SMarkus Pfeiffer 	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
287e355a444SMarkus Pfeiffer 	subvendor = pci_get_subvendor(dev);
288e355a444SMarkus Pfeiffer 	class = pci_get_class(dev);
289e355a444SMarkus Pfeiffer 	subclass = pci_get_subclass(dev);
290e355a444SMarkus Pfeiffer 
291e355a444SMarkus Pfeiffer 	result = ENXIO;
292e355a444SMarkus Pfeiffer 	for (i = 0; sdhci_devices[i].model != 0; i++) {
293e355a444SMarkus Pfeiffer 		if (sdhci_devices[i].model == model &&
294e355a444SMarkus Pfeiffer 		    (sdhci_devices[i].subvendor == 0xffff ||
295e355a444SMarkus Pfeiffer 		    sdhci_devices[i].subvendor == subvendor)) {
296e355a444SMarkus Pfeiffer 			device_set_desc(dev, sdhci_devices[i].desc);
297e355a444SMarkus Pfeiffer 			result = BUS_PROBE_DEFAULT;
298e355a444SMarkus Pfeiffer 			break;
299e355a444SMarkus Pfeiffer 		}
300e355a444SMarkus Pfeiffer 	}
301e355a444SMarkus Pfeiffer 	if (result == ENXIO && class == PCIC_BASEPERIPH &&
302e355a444SMarkus Pfeiffer 	    subclass == PCIS_BASEPERIPH_SDHC) {
303e355a444SMarkus Pfeiffer 		device_set_desc(dev, "Generic SD HCI");
304e355a444SMarkus Pfeiffer 		result = BUS_PROBE_GENERIC;
305e355a444SMarkus Pfeiffer 	}
306e355a444SMarkus Pfeiffer 
307e355a444SMarkus Pfeiffer 	return (result);
308e355a444SMarkus Pfeiffer }
309e355a444SMarkus Pfeiffer 
310e355a444SMarkus Pfeiffer static int
sdhci_pci_attach(device_t dev)311e355a444SMarkus Pfeiffer sdhci_pci_attach(device_t dev)
312e355a444SMarkus Pfeiffer {
313e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
314e355a444SMarkus Pfeiffer 	uint32_t model;
315e355a444SMarkus Pfeiffer 	uint16_t subvendor;
3162c2175b3SImre Vadász 	int bar, err, rid, slots, i;
3172c2175b3SImre Vadász #if defined(__DragonFly__)
3182c2175b3SImre Vadász 	int irq_flags;
3192c2175b3SImre Vadász #else
3202c2175b3SImre Vadász 	int count;
3212c2175b3SImre Vadász #endif
322e355a444SMarkus Pfeiffer 
323e355a444SMarkus Pfeiffer 	model = (uint32_t)pci_get_device(dev) << 16;
324e355a444SMarkus Pfeiffer 	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
325e355a444SMarkus Pfeiffer 	subvendor = pci_get_subvendor(dev);
326e355a444SMarkus Pfeiffer 	/* Apply chip specific quirks. */
327e355a444SMarkus Pfeiffer 	for (i = 0; sdhci_devices[i].model != 0; i++) {
328e355a444SMarkus Pfeiffer 		if (sdhci_devices[i].model == model &&
329e355a444SMarkus Pfeiffer 		    (sdhci_devices[i].subvendor == 0xffff ||
330e355a444SMarkus Pfeiffer 		    sdhci_devices[i].subvendor == subvendor)) {
331e355a444SMarkus Pfeiffer 			sc->quirks = sdhci_devices[i].quirks;
332e355a444SMarkus Pfeiffer 			break;
333e355a444SMarkus Pfeiffer 		}
334e355a444SMarkus Pfeiffer 	}
335*7ba10b88SImre Vadász 	sc->quirks &= ~sdhci_quirk_clear;
336*7ba10b88SImre Vadász 	sc->quirks |= sdhci_quirk_set;
337e355a444SMarkus Pfeiffer 	/* Some controllers need to be bumped into the right mode. */
338e355a444SMarkus Pfeiffer 	if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY)
339e355a444SMarkus Pfeiffer 		sdhci_lower_frequency(dev);
340e355a444SMarkus Pfeiffer 	/* Read slots info from PCI registers. */
341e355a444SMarkus Pfeiffer 	slots = pci_read_config(dev, PCI_SLOT_INFO, 1);
342e355a444SMarkus Pfeiffer 	bar = PCI_SLOT_INFO_FIRST_BAR(slots);
343e355a444SMarkus Pfeiffer 	slots = PCI_SLOT_INFO_SLOTS(slots);
344e355a444SMarkus Pfeiffer 	if (slots > 6 || bar > 5) {
345e355a444SMarkus Pfeiffer 		device_printf(dev, "Incorrect slots information (%d, %d).\n",
346e355a444SMarkus Pfeiffer 		    slots, bar);
347e355a444SMarkus Pfeiffer 		return (EINVAL);
348e355a444SMarkus Pfeiffer 	}
349e355a444SMarkus Pfeiffer 	/* Allocate IRQ. */
350e355a444SMarkus Pfeiffer 	rid = 0;
3512c2175b3SImre Vadász #if defined(__DragonFly__)
3522c2175b3SImre Vadász 	pci_alloc_1intr(dev, sdhci_enable_msi, &rid, &irq_flags);
3532c2175b3SImre Vadász 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, irq_flags);
3542c2175b3SImre Vadász #else
3552c2175b3SImre Vadász 	i = 1;
356e355a444SMarkus Pfeiffer 	if (sdhci_enable_msi != 0) {
357e355a444SMarkus Pfeiffer 		count = pci_msi_count(dev);
358e355a444SMarkus Pfeiffer 		if (count >= 1) {
359e355a444SMarkus Pfeiffer 			count = 1;
360e355a444SMarkus Pfeiffer 			if (pci_alloc_msi(dev, &i, 1, count) == 0) {
361e355a444SMarkus Pfeiffer 				if (bootverbose)
362e355a444SMarkus Pfeiffer 					device_printf(dev, "MSI enabled\n");
363e355a444SMarkus Pfeiffer 				rid = 1;
364e355a444SMarkus Pfeiffer 			}
365e355a444SMarkus Pfeiffer 		}
366e355a444SMarkus Pfeiffer 	}
367e355a444SMarkus Pfeiffer 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
368e355a444SMarkus Pfeiffer 		RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE));
3692c2175b3SImre Vadász #endif
370e355a444SMarkus Pfeiffer 	if (sc->irq_res == NULL) {
371e355a444SMarkus Pfeiffer 		device_printf(dev, "Can't allocate IRQ\n");
372e355a444SMarkus Pfeiffer 		pci_release_msi(dev);
373e355a444SMarkus Pfeiffer 		return (ENOMEM);
374e355a444SMarkus Pfeiffer 	}
375e355a444SMarkus Pfeiffer 	/* Scan all slots. */
376e355a444SMarkus Pfeiffer 	for (i = 0; i < slots; i++) {
377e355a444SMarkus Pfeiffer 		struct sdhci_slot *slot = &sc->slots[sc->num_slots];
378e355a444SMarkus Pfeiffer 
379e355a444SMarkus Pfeiffer 		/* Allocate memory. */
380e355a444SMarkus Pfeiffer 		rid = PCIR_BAR(bar + i);
3814f29f02bSImre Vadász 		sc->mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
3824f29f02bSImre Vadász 		    &rid, RF_ACTIVE);
383e355a444SMarkus Pfeiffer 		if (sc->mem_res[i] == NULL) {
384e355a444SMarkus Pfeiffer 			device_printf(dev, "Can't allocate memory for slot %d\n", i);
385e355a444SMarkus Pfeiffer 			continue;
386e355a444SMarkus Pfeiffer 		}
387e355a444SMarkus Pfeiffer 
3884f29f02bSImre Vadász 		slot->quirks = sc->quirks;
3894f29f02bSImre Vadász 
39065704a46SImre Vadász 		if (sdhci_init_slot(dev, slot, i) != 0) {
39165704a46SImre Vadász 			memset(slot, 0, sizeof(*slot));
392e355a444SMarkus Pfeiffer 			continue;
39365704a46SImre Vadász 		}
394e355a444SMarkus Pfeiffer 
395e355a444SMarkus Pfeiffer 		sc->num_slots++;
396e355a444SMarkus Pfeiffer 	}
397e355a444SMarkus Pfeiffer 	device_printf(dev, "%d slot(s) allocated\n", sc->num_slots);
398e355a444SMarkus Pfeiffer 	/* Activate the interrupt */
399e355a444SMarkus Pfeiffer 	err = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE,
400e355a444SMarkus Pfeiffer 	    sdhci_pci_intr, sc, &sc->intrhand, NULL);
401e355a444SMarkus Pfeiffer 	if (err)
402e355a444SMarkus Pfeiffer 		device_printf(dev, "Can't setup IRQ\n");
403e355a444SMarkus Pfeiffer 	pci_enable_busmaster(dev);
404e355a444SMarkus Pfeiffer 	/* Process cards detection. */
405e355a444SMarkus Pfeiffer 	for (i = 0; i < sc->num_slots; i++) {
406e355a444SMarkus Pfeiffer 		struct sdhci_slot *slot = &sc->slots[i];
407e355a444SMarkus Pfeiffer 
408e355a444SMarkus Pfeiffer 		sdhci_start_slot(slot);
409e355a444SMarkus Pfeiffer 	}
410e355a444SMarkus Pfeiffer 
411e355a444SMarkus Pfeiffer 	return (0);
412e355a444SMarkus Pfeiffer }
413e355a444SMarkus Pfeiffer 
414e355a444SMarkus Pfeiffer static int
sdhci_pci_detach(device_t dev)415e355a444SMarkus Pfeiffer sdhci_pci_detach(device_t dev)
416e355a444SMarkus Pfeiffer {
417e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
418e355a444SMarkus Pfeiffer 	int i;
419e355a444SMarkus Pfeiffer 
420e355a444SMarkus Pfeiffer 	bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
421e355a444SMarkus Pfeiffer 	bus_release_resource(dev, SYS_RES_IRQ,
422e355a444SMarkus Pfeiffer 	    rman_get_rid(sc->irq_res), sc->irq_res);
423e355a444SMarkus Pfeiffer 	pci_release_msi(dev);
424e355a444SMarkus Pfeiffer 
425e355a444SMarkus Pfeiffer 	for (i = 0; i < sc->num_slots; i++) {
426e355a444SMarkus Pfeiffer 		struct sdhci_slot *slot = &sc->slots[i];
427e355a444SMarkus Pfeiffer 
428e355a444SMarkus Pfeiffer 		sdhci_cleanup_slot(slot);
429e355a444SMarkus Pfeiffer 		bus_release_resource(dev, SYS_RES_MEMORY,
430e355a444SMarkus Pfeiffer 		    rman_get_rid(sc->mem_res[i]), sc->mem_res[i]);
431e355a444SMarkus Pfeiffer 	}
4324f29f02bSImre Vadász 	if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY)
4334f29f02bSImre Vadász 		sdhci_restore_frequency(dev);
4344f29f02bSImre Vadász 	return (0);
4354f29f02bSImre Vadász }
4364f29f02bSImre Vadász 
4374f29f02bSImre Vadász static int
sdhci_pci_shutdown(device_t dev)4384f29f02bSImre Vadász sdhci_pci_shutdown(device_t dev)
4394f29f02bSImre Vadász {
4404f29f02bSImre Vadász 	struct sdhci_pci_softc *sc = device_get_softc(dev);
4414f29f02bSImre Vadász 
4424f29f02bSImre Vadász 	if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY)
4434f29f02bSImre Vadász 		sdhci_restore_frequency(dev);
444e355a444SMarkus Pfeiffer 	return (0);
445e355a444SMarkus Pfeiffer }
446e355a444SMarkus Pfeiffer 
447e355a444SMarkus Pfeiffer static int
sdhci_pci_suspend(device_t dev)448e355a444SMarkus Pfeiffer sdhci_pci_suspend(device_t dev)
449e355a444SMarkus Pfeiffer {
450e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
451e355a444SMarkus Pfeiffer 	int i, err;
452e355a444SMarkus Pfeiffer 
453e355a444SMarkus Pfeiffer 	err = bus_generic_suspend(dev);
454e355a444SMarkus Pfeiffer 	if (err)
455e355a444SMarkus Pfeiffer 		return (err);
456e355a444SMarkus Pfeiffer 	for (i = 0; i < sc->num_slots; i++)
457e355a444SMarkus Pfeiffer 		sdhci_generic_suspend(&sc->slots[i]);
458e355a444SMarkus Pfeiffer 	return (0);
459e355a444SMarkus Pfeiffer }
460e355a444SMarkus Pfeiffer 
461e355a444SMarkus Pfeiffer static int
sdhci_pci_resume(device_t dev)462e355a444SMarkus Pfeiffer sdhci_pci_resume(device_t dev)
463e355a444SMarkus Pfeiffer {
464e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = device_get_softc(dev);
465e355a444SMarkus Pfeiffer 	int i;
466e355a444SMarkus Pfeiffer 
467e355a444SMarkus Pfeiffer 	for (i = 0; i < sc->num_slots; i++)
468e355a444SMarkus Pfeiffer 		sdhci_generic_resume(&sc->slots[i]);
469e355a444SMarkus Pfeiffer 	return (bus_generic_resume(dev));
470e355a444SMarkus Pfeiffer }
471e355a444SMarkus Pfeiffer 
472e355a444SMarkus Pfeiffer static void
sdhci_pci_intr(void * arg)473e355a444SMarkus Pfeiffer sdhci_pci_intr(void *arg)
474e355a444SMarkus Pfeiffer {
475e355a444SMarkus Pfeiffer 	struct sdhci_pci_softc *sc = (struct sdhci_pci_softc *)arg;
476e355a444SMarkus Pfeiffer 	int i;
477e355a444SMarkus Pfeiffer 
478e355a444SMarkus Pfeiffer 	for (i = 0; i < sc->num_slots; i++) {
479e355a444SMarkus Pfeiffer 		struct sdhci_slot *slot = &sc->slots[i];
480e355a444SMarkus Pfeiffer 		sdhci_generic_intr(slot);
481e355a444SMarkus Pfeiffer 	}
482e355a444SMarkus Pfeiffer }
483e355a444SMarkus Pfeiffer 
484e355a444SMarkus Pfeiffer static device_method_t sdhci_methods[] = {
485e355a444SMarkus Pfeiffer 	/* device_if */
486e355a444SMarkus Pfeiffer 	DEVMETHOD(device_probe, sdhci_pci_probe),
487e355a444SMarkus Pfeiffer 	DEVMETHOD(device_attach, sdhci_pci_attach),
488e355a444SMarkus Pfeiffer 	DEVMETHOD(device_detach, sdhci_pci_detach),
4894f29f02bSImre Vadász 	DEVMETHOD(device_shutdown, sdhci_pci_shutdown),
490e355a444SMarkus Pfeiffer 	DEVMETHOD(device_suspend, sdhci_pci_suspend),
491e355a444SMarkus Pfeiffer 	DEVMETHOD(device_resume, sdhci_pci_resume),
492e355a444SMarkus Pfeiffer 
493e355a444SMarkus Pfeiffer 	/* Bus interface */
494e355a444SMarkus Pfeiffer 	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
495e355a444SMarkus Pfeiffer 	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
496e355a444SMarkus Pfeiffer 
497e355a444SMarkus Pfeiffer 	/* mmcbr_if */
498e355a444SMarkus Pfeiffer 	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
499*7ba10b88SImre Vadász 	DEVMETHOD(mmcbr_switch_vccq,	sdhci_generic_switch_vccq),
500e355a444SMarkus Pfeiffer 	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
501e355a444SMarkus Pfeiffer 	DEVMETHOD(mmcbr_get_ro,		sdhci_generic_get_ro),
502e355a444SMarkus Pfeiffer 	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
503e355a444SMarkus Pfeiffer 	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
504e355a444SMarkus Pfeiffer 
505*7ba10b88SImre Vadász 	/* SDHCI accessors */
506e355a444SMarkus Pfeiffer 	DEVMETHOD(sdhci_read_1,		sdhci_pci_read_1),
507e355a444SMarkus Pfeiffer 	DEVMETHOD(sdhci_read_2,		sdhci_pci_read_2),
508e355a444SMarkus Pfeiffer 	DEVMETHOD(sdhci_read_4,		sdhci_pci_read_4),
509e355a444SMarkus Pfeiffer 	DEVMETHOD(sdhci_read_multi_4,	sdhci_pci_read_multi_4),
510e355a444SMarkus Pfeiffer 	DEVMETHOD(sdhci_write_1,	sdhci_pci_write_1),
511e355a444SMarkus Pfeiffer 	DEVMETHOD(sdhci_write_2,	sdhci_pci_write_2),
512e355a444SMarkus Pfeiffer 	DEVMETHOD(sdhci_write_4,	sdhci_pci_write_4),
513e355a444SMarkus Pfeiffer 	DEVMETHOD(sdhci_write_multi_4,	sdhci_pci_write_multi_4),
514*7ba10b88SImre Vadász 	DEVMETHOD(sdhci_set_uhs_timing,	sdhci_generic_set_uhs_timing),
515e355a444SMarkus Pfeiffer 
516e355a444SMarkus Pfeiffer 	DEVMETHOD_END
517e355a444SMarkus Pfeiffer };
518e355a444SMarkus Pfeiffer 
519e355a444SMarkus Pfeiffer static driver_t sdhci_pci_driver = {
520e355a444SMarkus Pfeiffer 	"sdhci_pci",
521e355a444SMarkus Pfeiffer 	sdhci_methods,
522e355a444SMarkus Pfeiffer 	sizeof(struct sdhci_pci_softc),
523e355a444SMarkus Pfeiffer };
524e355a444SMarkus Pfeiffer static devclass_t sdhci_pci_devclass;
525e355a444SMarkus Pfeiffer 
526e355a444SMarkus Pfeiffer DRIVER_MODULE(sdhci_pci, pci, sdhci_pci_driver, sdhci_pci_devclass, NULL,
527e355a444SMarkus Pfeiffer     NULL);
528e355a444SMarkus Pfeiffer MODULE_DEPEND(sdhci_pci, sdhci, 1, 1, 1);
529