xref: /freebsd/sys/dev/sdhci/sdhci_pci.c (revision d6b3aaf842aa37e5c10a6d00dff5a2409fdf59d5)
1*d6b3aaf8SOleksandr Tymoshenko /*-
2*d6b3aaf8SOleksandr Tymoshenko  * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
3*d6b3aaf8SOleksandr Tymoshenko  * All rights reserved.
4*d6b3aaf8SOleksandr Tymoshenko  *
5*d6b3aaf8SOleksandr Tymoshenko  * Redistribution and use in source and binary forms, with or without
6*d6b3aaf8SOleksandr Tymoshenko  * modification, are permitted provided that the following conditions
7*d6b3aaf8SOleksandr Tymoshenko  * are met:
8*d6b3aaf8SOleksandr Tymoshenko  * 1. Redistributions of source code must retain the above copyright
9*d6b3aaf8SOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer.
10*d6b3aaf8SOleksandr Tymoshenko  * 2. Redistributions in binary form must reproduce the above copyright
11*d6b3aaf8SOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer in the
12*d6b3aaf8SOleksandr Tymoshenko  *    documentation and/or other materials provided with the distribution.
13*d6b3aaf8SOleksandr Tymoshenko  *
14*d6b3aaf8SOleksandr Tymoshenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*d6b3aaf8SOleksandr Tymoshenko  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*d6b3aaf8SOleksandr Tymoshenko  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*d6b3aaf8SOleksandr Tymoshenko  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*d6b3aaf8SOleksandr Tymoshenko  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*d6b3aaf8SOleksandr Tymoshenko  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*d6b3aaf8SOleksandr Tymoshenko  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*d6b3aaf8SOleksandr Tymoshenko  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*d6b3aaf8SOleksandr Tymoshenko  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*d6b3aaf8SOleksandr Tymoshenko  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*d6b3aaf8SOleksandr Tymoshenko  */
25*d6b3aaf8SOleksandr Tymoshenko 
26*d6b3aaf8SOleksandr Tymoshenko #include <sys/cdefs.h>
27*d6b3aaf8SOleksandr Tymoshenko __FBSDID("$FreeBSD$");
28*d6b3aaf8SOleksandr Tymoshenko 
29*d6b3aaf8SOleksandr Tymoshenko #include <sys/param.h>
30*d6b3aaf8SOleksandr Tymoshenko #include <sys/systm.h>
31*d6b3aaf8SOleksandr Tymoshenko #include <sys/bus.h>
32*d6b3aaf8SOleksandr Tymoshenko #include <sys/conf.h>
33*d6b3aaf8SOleksandr Tymoshenko #include <sys/kernel.h>
34*d6b3aaf8SOleksandr Tymoshenko #include <sys/lock.h>
35*d6b3aaf8SOleksandr Tymoshenko #include <sys/module.h>
36*d6b3aaf8SOleksandr Tymoshenko #include <sys/mutex.h>
37*d6b3aaf8SOleksandr Tymoshenko #include <sys/resource.h>
38*d6b3aaf8SOleksandr Tymoshenko #include <sys/rman.h>
39*d6b3aaf8SOleksandr Tymoshenko #include <sys/sysctl.h>
40*d6b3aaf8SOleksandr Tymoshenko #include <sys/taskqueue.h>
41*d6b3aaf8SOleksandr Tymoshenko 
42*d6b3aaf8SOleksandr Tymoshenko #include <dev/pci/pcireg.h>
43*d6b3aaf8SOleksandr Tymoshenko #include <dev/pci/pcivar.h>
44*d6b3aaf8SOleksandr Tymoshenko 
45*d6b3aaf8SOleksandr Tymoshenko #include <machine/bus.h>
46*d6b3aaf8SOleksandr Tymoshenko #include <machine/resource.h>
47*d6b3aaf8SOleksandr Tymoshenko #include <machine/stdarg.h>
48*d6b3aaf8SOleksandr Tymoshenko 
49*d6b3aaf8SOleksandr Tymoshenko #include <dev/mmc/bridge.h>
50*d6b3aaf8SOleksandr Tymoshenko #include <dev/mmc/mmcreg.h>
51*d6b3aaf8SOleksandr Tymoshenko #include <dev/mmc/mmcbrvar.h>
52*d6b3aaf8SOleksandr Tymoshenko 
53*d6b3aaf8SOleksandr Tymoshenko #include "sdhci.h"
54*d6b3aaf8SOleksandr Tymoshenko #include "mmcbr_if.h"
55*d6b3aaf8SOleksandr Tymoshenko #include "sdhci_if.h"
56*d6b3aaf8SOleksandr Tymoshenko 
57*d6b3aaf8SOleksandr Tymoshenko /*
58*d6b3aaf8SOleksandr Tymoshenko  * PCI registers
59*d6b3aaf8SOleksandr Tymoshenko  */
60*d6b3aaf8SOleksandr Tymoshenko 
61*d6b3aaf8SOleksandr Tymoshenko #define PCI_SDHCI_IFPIO			0x00
62*d6b3aaf8SOleksandr Tymoshenko #define PCI_SDHCI_IFDMA			0x01
63*d6b3aaf8SOleksandr Tymoshenko #define PCI_SDHCI_IFVENDOR		0x02
64*d6b3aaf8SOleksandr Tymoshenko 
65*d6b3aaf8SOleksandr Tymoshenko #define PCI_SLOT_INFO			0x40	/* 8 bits */
66*d6b3aaf8SOleksandr Tymoshenko #define  PCI_SLOT_INFO_SLOTS(x)		(((x >> 4) & 7) + 1)
67*d6b3aaf8SOleksandr Tymoshenko #define  PCI_SLOT_INFO_FIRST_BAR(x)	((x) & 7)
68*d6b3aaf8SOleksandr Tymoshenko 
69*d6b3aaf8SOleksandr Tymoshenko /*
70*d6b3aaf8SOleksandr Tymoshenko  * RICOH specific PCI registers
71*d6b3aaf8SOleksandr Tymoshenko  */
72*d6b3aaf8SOleksandr Tymoshenko #define	SDHC_PCI_MODE_KEY		0xf9
73*d6b3aaf8SOleksandr Tymoshenko #define	SDHC_PCI_MODE			0x150
74*d6b3aaf8SOleksandr Tymoshenko #define	SDHC_PCI_MODE_SD20		0x10
75*d6b3aaf8SOleksandr Tymoshenko #define	SDHC_PCI_BASE_FREQ_KEY		0xfc
76*d6b3aaf8SOleksandr Tymoshenko #define	SDHC_PCI_BASE_FREQ		0xe1
77*d6b3aaf8SOleksandr Tymoshenko 
78*d6b3aaf8SOleksandr Tymoshenko static const struct sdhci_device {
79*d6b3aaf8SOleksandr Tymoshenko 	uint32_t	model;
80*d6b3aaf8SOleksandr Tymoshenko 	uint16_t	subvendor;
81*d6b3aaf8SOleksandr Tymoshenko 	char		*desc;
82*d6b3aaf8SOleksandr Tymoshenko 	u_int		quirks;
83*d6b3aaf8SOleksandr Tymoshenko } sdhci_devices[] = {
84*d6b3aaf8SOleksandr Tymoshenko 	{ 0x08221180, 	0xffff,	"RICOH R5C822 SD",
85*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_FORCE_DMA },
86*d6b3aaf8SOleksandr Tymoshenko 	{ 0xe8221180, 	0xffff,	"RICOH SD",
87*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_FORCE_DMA },
88*d6b3aaf8SOleksandr Tymoshenko 	{ 0xe8231180, 	0xffff,	"RICOH R5CE823 SD",
89*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_LOWER_FREQUENCY },
90*d6b3aaf8SOleksandr Tymoshenko 	{ 0x8034104c, 	0xffff, "TI XX21/XX11 SD",
91*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_FORCE_DMA },
92*d6b3aaf8SOleksandr Tymoshenko 	{ 0x05501524, 	0xffff, "ENE CB712 SD",
93*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_BROKEN_TIMINGS },
94*d6b3aaf8SOleksandr Tymoshenko 	{ 0x05511524, 	0xffff, "ENE CB712 SD 2",
95*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_BROKEN_TIMINGS },
96*d6b3aaf8SOleksandr Tymoshenko 	{ 0x07501524, 	0xffff, "ENE CB714 SD",
97*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_RESET_ON_IOS |
98*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_BROKEN_TIMINGS },
99*d6b3aaf8SOleksandr Tymoshenko 	{ 0x07511524, 	0xffff, "ENE CB714 SD 2",
100*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_RESET_ON_IOS |
101*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_BROKEN_TIMINGS },
102*d6b3aaf8SOleksandr Tymoshenko 	{ 0x410111ab, 	0xffff, "Marvell CaFe SD",
103*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_INCR_TIMEOUT_CONTROL },
104*d6b3aaf8SOleksandr Tymoshenko 	{ 0x2381197B, 	0xffff,	"JMicron JMB38X SD",
105*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_32BIT_DMA_SIZE |
106*d6b3aaf8SOleksandr Tymoshenko 	    SDHCI_QUIRK_RESET_AFTER_REQUEST },
107*d6b3aaf8SOleksandr Tymoshenko 	{ 0,		0xffff,	NULL,
108*d6b3aaf8SOleksandr Tymoshenko 	    0 }
109*d6b3aaf8SOleksandr Tymoshenko };
110*d6b3aaf8SOleksandr Tymoshenko 
111*d6b3aaf8SOleksandr Tymoshenko struct sdhci_pci_softc {
112*d6b3aaf8SOleksandr Tymoshenko 	device_t	dev;		/* Controller device */
113*d6b3aaf8SOleksandr Tymoshenko 	u_int		quirks;		/* Chip specific quirks */
114*d6b3aaf8SOleksandr Tymoshenko 	struct resource *irq_res;	/* IRQ resource */
115*d6b3aaf8SOleksandr Tymoshenko 	int 		irq_rid;
116*d6b3aaf8SOleksandr Tymoshenko 	void 		*intrhand;	/* Interrupt handle */
117*d6b3aaf8SOleksandr Tymoshenko 
118*d6b3aaf8SOleksandr Tymoshenko 	int		num_slots;	/* Number of slots on this controller */
119*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_slot slots[6];
120*d6b3aaf8SOleksandr Tymoshenko 	struct resource	*mem_res[6];	/* Memory resource */
121*d6b3aaf8SOleksandr Tymoshenko 	int		mem_rid[6];
122*d6b3aaf8SOleksandr Tymoshenko };
123*d6b3aaf8SOleksandr Tymoshenko 
124*d6b3aaf8SOleksandr Tymoshenko static SYSCTL_NODE(_hw, OID_AUTO, sdhci_pci, CTLFLAG_RD, 0, "sdhci PCI driver");
125*d6b3aaf8SOleksandr Tymoshenko 
126*d6b3aaf8SOleksandr Tymoshenko int	sdhci_pci_debug;
127*d6b3aaf8SOleksandr Tymoshenko TUNABLE_INT("hw.sdhci_pci.debug", &sdhci_pci_debug);
128*d6b3aaf8SOleksandr Tymoshenko SYSCTL_INT(_hw_sdhci_pci, OID_AUTO, debug, CTLFLAG_RW, &sdhci_pci_debug, 0, "Debug level");
129*d6b3aaf8SOleksandr Tymoshenko 
130*d6b3aaf8SOleksandr Tymoshenko static uint8_t
131*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
132*d6b3aaf8SOleksandr Tymoshenko {
133*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
134*d6b3aaf8SOleksandr Tymoshenko 
135*d6b3aaf8SOleksandr Tymoshenko 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
136*d6b3aaf8SOleksandr Tymoshenko 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
137*d6b3aaf8SOleksandr Tymoshenko 	return bus_read_1(sc->mem_res[slot->num], off);
138*d6b3aaf8SOleksandr Tymoshenko }
139*d6b3aaf8SOleksandr Tymoshenko 
140*d6b3aaf8SOleksandr Tymoshenko static void
141*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val)
142*d6b3aaf8SOleksandr Tymoshenko {
143*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
144*d6b3aaf8SOleksandr Tymoshenko 
145*d6b3aaf8SOleksandr Tymoshenko 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
146*d6b3aaf8SOleksandr Tymoshenko 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
147*d6b3aaf8SOleksandr Tymoshenko 	bus_write_1(sc->mem_res[slot->num], off, val);
148*d6b3aaf8SOleksandr Tymoshenko }
149*d6b3aaf8SOleksandr Tymoshenko 
150*d6b3aaf8SOleksandr Tymoshenko static uint16_t
151*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
152*d6b3aaf8SOleksandr Tymoshenko {
153*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
154*d6b3aaf8SOleksandr Tymoshenko 
155*d6b3aaf8SOleksandr Tymoshenko 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
156*d6b3aaf8SOleksandr Tymoshenko 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
157*d6b3aaf8SOleksandr Tymoshenko 	return bus_read_2(sc->mem_res[slot->num], off);
158*d6b3aaf8SOleksandr Tymoshenko }
159*d6b3aaf8SOleksandr Tymoshenko 
160*d6b3aaf8SOleksandr Tymoshenko static void
161*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
162*d6b3aaf8SOleksandr Tymoshenko {
163*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
164*d6b3aaf8SOleksandr Tymoshenko 
165*d6b3aaf8SOleksandr Tymoshenko 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
166*d6b3aaf8SOleksandr Tymoshenko 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
167*d6b3aaf8SOleksandr Tymoshenko 	bus_write_2(sc->mem_res[slot->num], off, val);
168*d6b3aaf8SOleksandr Tymoshenko }
169*d6b3aaf8SOleksandr Tymoshenko 
170*d6b3aaf8SOleksandr Tymoshenko static uint32_t
171*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
172*d6b3aaf8SOleksandr Tymoshenko {
173*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
174*d6b3aaf8SOleksandr Tymoshenko 
175*d6b3aaf8SOleksandr Tymoshenko 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
176*d6b3aaf8SOleksandr Tymoshenko 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
177*d6b3aaf8SOleksandr Tymoshenko 	return bus_read_4(sc->mem_res[slot->num], off);
178*d6b3aaf8SOleksandr Tymoshenko }
179*d6b3aaf8SOleksandr Tymoshenko 
180*d6b3aaf8SOleksandr Tymoshenko static void
181*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
182*d6b3aaf8SOleksandr Tymoshenko {
183*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
184*d6b3aaf8SOleksandr Tymoshenko 
185*d6b3aaf8SOleksandr Tymoshenko 	bus_barrier(sc->mem_res[slot->num], 0, 0xFF,
186*d6b3aaf8SOleksandr Tymoshenko 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
187*d6b3aaf8SOleksandr Tymoshenko 	bus_write_4(sc->mem_res[slot->num], off, val);
188*d6b3aaf8SOleksandr Tymoshenko }
189*d6b3aaf8SOleksandr Tymoshenko 
190*d6b3aaf8SOleksandr Tymoshenko static void
191*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_read_multi_4(device_t dev, struct sdhci_slot *slot,
192*d6b3aaf8SOleksandr Tymoshenko     bus_size_t off, uint32_t *data, bus_size_t count)
193*d6b3aaf8SOleksandr Tymoshenko {
194*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
195*d6b3aaf8SOleksandr Tymoshenko 
196*d6b3aaf8SOleksandr Tymoshenko 	bus_read_multi_stream_4(sc->mem_res[slot->num], off, data, count);
197*d6b3aaf8SOleksandr Tymoshenko }
198*d6b3aaf8SOleksandr Tymoshenko 
199*d6b3aaf8SOleksandr Tymoshenko static void
200*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_write_multi_4(device_t dev, struct sdhci_slot *slot,
201*d6b3aaf8SOleksandr Tymoshenko     bus_size_t off, uint32_t *data, bus_size_t count)
202*d6b3aaf8SOleksandr Tymoshenko {
203*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
204*d6b3aaf8SOleksandr Tymoshenko 
205*d6b3aaf8SOleksandr Tymoshenko 	bus_write_multi_stream_4(sc->mem_res[slot->num], off, data, count);
206*d6b3aaf8SOleksandr Tymoshenko }
207*d6b3aaf8SOleksandr Tymoshenko 
208*d6b3aaf8SOleksandr Tymoshenko static void sdhci_pci_intr(void *arg);
209*d6b3aaf8SOleksandr Tymoshenko 
210*d6b3aaf8SOleksandr Tymoshenko static void
211*d6b3aaf8SOleksandr Tymoshenko sdhci_lower_frequency(device_t dev)
212*d6b3aaf8SOleksandr Tymoshenko {
213*d6b3aaf8SOleksandr Tymoshenko 
214*d6b3aaf8SOleksandr Tymoshenko 	/* Enable SD2.0 mode. */
215*d6b3aaf8SOleksandr Tymoshenko 	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0xfc, 1);
216*d6b3aaf8SOleksandr Tymoshenko 	pci_write_config(dev, SDHC_PCI_MODE, SDHC_PCI_MODE_SD20, 1);
217*d6b3aaf8SOleksandr Tymoshenko 	pci_write_config(dev, SDHC_PCI_MODE_KEY, 0x00, 1);
218*d6b3aaf8SOleksandr Tymoshenko 
219*d6b3aaf8SOleksandr Tymoshenko 	/*
220*d6b3aaf8SOleksandr Tymoshenko 	 * Some SD/MMC cards don't work with the default base
221*d6b3aaf8SOleksandr Tymoshenko 	 * clock frequency of 200MHz.  Lower it to 50Hz.
222*d6b3aaf8SOleksandr Tymoshenko 	 */
223*d6b3aaf8SOleksandr Tymoshenko 	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x01, 1);
224*d6b3aaf8SOleksandr Tymoshenko 	pci_write_config(dev, SDHC_PCI_BASE_FREQ, 50, 1);
225*d6b3aaf8SOleksandr Tymoshenko 	pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x00, 1);
226*d6b3aaf8SOleksandr Tymoshenko }
227*d6b3aaf8SOleksandr Tymoshenko 
228*d6b3aaf8SOleksandr Tymoshenko static int
229*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_probe(device_t dev)
230*d6b3aaf8SOleksandr Tymoshenko {
231*d6b3aaf8SOleksandr Tymoshenko 	uint32_t model;
232*d6b3aaf8SOleksandr Tymoshenko 	uint16_t subvendor;
233*d6b3aaf8SOleksandr Tymoshenko 	uint8_t class, subclass;
234*d6b3aaf8SOleksandr Tymoshenko 	int i, result;
235*d6b3aaf8SOleksandr Tymoshenko 
236*d6b3aaf8SOleksandr Tymoshenko 	model = (uint32_t)pci_get_device(dev) << 16;
237*d6b3aaf8SOleksandr Tymoshenko 	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
238*d6b3aaf8SOleksandr Tymoshenko 	subvendor = pci_get_subvendor(dev);
239*d6b3aaf8SOleksandr Tymoshenko 	class = pci_get_class(dev);
240*d6b3aaf8SOleksandr Tymoshenko 	subclass = pci_get_subclass(dev);
241*d6b3aaf8SOleksandr Tymoshenko 
242*d6b3aaf8SOleksandr Tymoshenko 	result = ENXIO;
243*d6b3aaf8SOleksandr Tymoshenko 	for (i = 0; sdhci_devices[i].model != 0; i++) {
244*d6b3aaf8SOleksandr Tymoshenko 		if (sdhci_devices[i].model == model &&
245*d6b3aaf8SOleksandr Tymoshenko 		    (sdhci_devices[i].subvendor == 0xffff ||
246*d6b3aaf8SOleksandr Tymoshenko 		    sdhci_devices[i].subvendor == subvendor)) {
247*d6b3aaf8SOleksandr Tymoshenko 			device_set_desc(dev, sdhci_devices[i].desc);
248*d6b3aaf8SOleksandr Tymoshenko 			result = BUS_PROBE_DEFAULT;
249*d6b3aaf8SOleksandr Tymoshenko 			break;
250*d6b3aaf8SOleksandr Tymoshenko 		}
251*d6b3aaf8SOleksandr Tymoshenko 	}
252*d6b3aaf8SOleksandr Tymoshenko 	if (result == ENXIO && class == PCIC_BASEPERIPH &&
253*d6b3aaf8SOleksandr Tymoshenko 	    subclass == PCIS_BASEPERIPH_SDHC) {
254*d6b3aaf8SOleksandr Tymoshenko 		device_set_desc(dev, "Generic SD HCI");
255*d6b3aaf8SOleksandr Tymoshenko 		result = BUS_PROBE_GENERIC;
256*d6b3aaf8SOleksandr Tymoshenko 	}
257*d6b3aaf8SOleksandr Tymoshenko 
258*d6b3aaf8SOleksandr Tymoshenko 	return (result);
259*d6b3aaf8SOleksandr Tymoshenko }
260*d6b3aaf8SOleksandr Tymoshenko 
261*d6b3aaf8SOleksandr Tymoshenko static int
262*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_attach(device_t dev)
263*d6b3aaf8SOleksandr Tymoshenko {
264*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
265*d6b3aaf8SOleksandr Tymoshenko 	uint32_t model;
266*d6b3aaf8SOleksandr Tymoshenko 	uint16_t subvendor;
267*d6b3aaf8SOleksandr Tymoshenko 	uint8_t class, subclass, progif;
268*d6b3aaf8SOleksandr Tymoshenko 	int err, slots, bar, i;
269*d6b3aaf8SOleksandr Tymoshenko 
270*d6b3aaf8SOleksandr Tymoshenko 	sc->dev = dev;
271*d6b3aaf8SOleksandr Tymoshenko 	model = (uint32_t)pci_get_device(dev) << 16;
272*d6b3aaf8SOleksandr Tymoshenko 	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
273*d6b3aaf8SOleksandr Tymoshenko 	subvendor = pci_get_subvendor(dev);
274*d6b3aaf8SOleksandr Tymoshenko 	class = pci_get_class(dev);
275*d6b3aaf8SOleksandr Tymoshenko 	subclass = pci_get_subclass(dev);
276*d6b3aaf8SOleksandr Tymoshenko 	progif = pci_get_progif(dev);
277*d6b3aaf8SOleksandr Tymoshenko 	/* Apply chip specific quirks. */
278*d6b3aaf8SOleksandr Tymoshenko 	for (i = 0; sdhci_devices[i].model != 0; i++) {
279*d6b3aaf8SOleksandr Tymoshenko 		if (sdhci_devices[i].model == model &&
280*d6b3aaf8SOleksandr Tymoshenko 		    (sdhci_devices[i].subvendor == 0xffff ||
281*d6b3aaf8SOleksandr Tymoshenko 		    sdhci_devices[i].subvendor == subvendor)) {
282*d6b3aaf8SOleksandr Tymoshenko 			sc->quirks = sdhci_devices[i].quirks;
283*d6b3aaf8SOleksandr Tymoshenko 			break;
284*d6b3aaf8SOleksandr Tymoshenko 		}
285*d6b3aaf8SOleksandr Tymoshenko 	}
286*d6b3aaf8SOleksandr Tymoshenko 	/* Some controllers need to be bumped into the right mode. */
287*d6b3aaf8SOleksandr Tymoshenko 	if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY)
288*d6b3aaf8SOleksandr Tymoshenko 		sdhci_lower_frequency(dev);
289*d6b3aaf8SOleksandr Tymoshenko 	/* Read slots info from PCI registers. */
290*d6b3aaf8SOleksandr Tymoshenko 	slots = pci_read_config(dev, PCI_SLOT_INFO, 1);
291*d6b3aaf8SOleksandr Tymoshenko 	bar = PCI_SLOT_INFO_FIRST_BAR(slots);
292*d6b3aaf8SOleksandr Tymoshenko 	slots = PCI_SLOT_INFO_SLOTS(slots);
293*d6b3aaf8SOleksandr Tymoshenko 	if (slots > 6 || bar > 5) {
294*d6b3aaf8SOleksandr Tymoshenko 		device_printf(dev, "Incorrect slots information (%d, %d).\n",
295*d6b3aaf8SOleksandr Tymoshenko 		    slots, bar);
296*d6b3aaf8SOleksandr Tymoshenko 		return (EINVAL);
297*d6b3aaf8SOleksandr Tymoshenko 	}
298*d6b3aaf8SOleksandr Tymoshenko 	/* Allocate IRQ. */
299*d6b3aaf8SOleksandr Tymoshenko 	sc->irq_rid = 0;
300*d6b3aaf8SOleksandr Tymoshenko 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
301*d6b3aaf8SOleksandr Tymoshenko 	    RF_SHAREABLE | RF_ACTIVE);
302*d6b3aaf8SOleksandr Tymoshenko 	if (sc->irq_res == NULL) {
303*d6b3aaf8SOleksandr Tymoshenko 		device_printf(dev, "Can't allocate IRQ\n");
304*d6b3aaf8SOleksandr Tymoshenko 		return (ENOMEM);
305*d6b3aaf8SOleksandr Tymoshenko 	}
306*d6b3aaf8SOleksandr Tymoshenko 	/* Scan all slots. */
307*d6b3aaf8SOleksandr Tymoshenko 	for (i = 0; i < slots; i++) {
308*d6b3aaf8SOleksandr Tymoshenko 		struct sdhci_slot *slot = &sc->slots[sc->num_slots];
309*d6b3aaf8SOleksandr Tymoshenko 
310*d6b3aaf8SOleksandr Tymoshenko 		/* Allocate memory. */
311*d6b3aaf8SOleksandr Tymoshenko 		sc->mem_rid[i] = PCIR_BAR(bar + i);
312*d6b3aaf8SOleksandr Tymoshenko 		sc->mem_res[i] = bus_alloc_resource(dev,
313*d6b3aaf8SOleksandr Tymoshenko 		    SYS_RES_MEMORY, &(sc->mem_rid[i]), 0ul, ~0ul, 0x100, RF_ACTIVE);
314*d6b3aaf8SOleksandr Tymoshenko 		if (sc->mem_res[i] == NULL) {
315*d6b3aaf8SOleksandr Tymoshenko 			device_printf(dev, "Can't allocate memory for slot %d\n", i);
316*d6b3aaf8SOleksandr Tymoshenko 			continue;
317*d6b3aaf8SOleksandr Tymoshenko 		}
318*d6b3aaf8SOleksandr Tymoshenko 
319*d6b3aaf8SOleksandr Tymoshenko 		if (sdhci_init_slot(dev, slot, i) != 0)
320*d6b3aaf8SOleksandr Tymoshenko 			continue;
321*d6b3aaf8SOleksandr Tymoshenko 
322*d6b3aaf8SOleksandr Tymoshenko 
323*d6b3aaf8SOleksandr Tymoshenko 		sc->num_slots++;
324*d6b3aaf8SOleksandr Tymoshenko 	}
325*d6b3aaf8SOleksandr Tymoshenko 	device_printf(dev, "%d slot(s) allocated\n", sc->num_slots);
326*d6b3aaf8SOleksandr Tymoshenko 	/* Activate the interrupt */
327*d6b3aaf8SOleksandr Tymoshenko 	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
328*d6b3aaf8SOleksandr Tymoshenko 	    NULL, sdhci_pci_intr, sc, &sc->intrhand);
329*d6b3aaf8SOleksandr Tymoshenko 	if (err)
330*d6b3aaf8SOleksandr Tymoshenko 		device_printf(dev, "Can't setup IRQ\n");
331*d6b3aaf8SOleksandr Tymoshenko 	pci_enable_busmaster(dev);
332*d6b3aaf8SOleksandr Tymoshenko 	/* Process cards detection. */
333*d6b3aaf8SOleksandr Tymoshenko 	for (i = 0; i < sc->num_slots; i++) {
334*d6b3aaf8SOleksandr Tymoshenko 		struct sdhci_slot *slot = &sc->slots[i];
335*d6b3aaf8SOleksandr Tymoshenko 
336*d6b3aaf8SOleksandr Tymoshenko 		sdhci_start_slot(slot);
337*d6b3aaf8SOleksandr Tymoshenko 	}
338*d6b3aaf8SOleksandr Tymoshenko 
339*d6b3aaf8SOleksandr Tymoshenko 	return (0);
340*d6b3aaf8SOleksandr Tymoshenko }
341*d6b3aaf8SOleksandr Tymoshenko 
342*d6b3aaf8SOleksandr Tymoshenko static int
343*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_detach(device_t dev)
344*d6b3aaf8SOleksandr Tymoshenko {
345*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
346*d6b3aaf8SOleksandr Tymoshenko 	int i;
347*d6b3aaf8SOleksandr Tymoshenko 
348*d6b3aaf8SOleksandr Tymoshenko 	bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
349*d6b3aaf8SOleksandr Tymoshenko 	bus_release_resource(dev, SYS_RES_IRQ,
350*d6b3aaf8SOleksandr Tymoshenko 	    sc->irq_rid, sc->irq_res);
351*d6b3aaf8SOleksandr Tymoshenko 
352*d6b3aaf8SOleksandr Tymoshenko 	for (i = 0; i < sc->num_slots; i++) {
353*d6b3aaf8SOleksandr Tymoshenko 		struct sdhci_slot *slot = &sc->slots[i];
354*d6b3aaf8SOleksandr Tymoshenko 
355*d6b3aaf8SOleksandr Tymoshenko 		sdhci_cleanup_slot(slot);
356*d6b3aaf8SOleksandr Tymoshenko 		bus_release_resource(dev, SYS_RES_MEMORY,
357*d6b3aaf8SOleksandr Tymoshenko 		    sc->mem_rid[i], sc->mem_res[i]);
358*d6b3aaf8SOleksandr Tymoshenko 	}
359*d6b3aaf8SOleksandr Tymoshenko 	return (0);
360*d6b3aaf8SOleksandr Tymoshenko }
361*d6b3aaf8SOleksandr Tymoshenko 
362*d6b3aaf8SOleksandr Tymoshenko static int
363*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_suspend(device_t dev)
364*d6b3aaf8SOleksandr Tymoshenko {
365*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
366*d6b3aaf8SOleksandr Tymoshenko 	int i, err;
367*d6b3aaf8SOleksandr Tymoshenko 
368*d6b3aaf8SOleksandr Tymoshenko 	err = bus_generic_suspend(dev);
369*d6b3aaf8SOleksandr Tymoshenko 	if (err)
370*d6b3aaf8SOleksandr Tymoshenko 		return (err);
371*d6b3aaf8SOleksandr Tymoshenko 	for (i = 0; i < sc->num_slots; i++)
372*d6b3aaf8SOleksandr Tymoshenko 		 sdhci_generic_suspend(&sc->slots[i]);
373*d6b3aaf8SOleksandr Tymoshenko 	return (0);
374*d6b3aaf8SOleksandr Tymoshenko }
375*d6b3aaf8SOleksandr Tymoshenko 
376*d6b3aaf8SOleksandr Tymoshenko static int
377*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_resume(device_t dev)
378*d6b3aaf8SOleksandr Tymoshenko {
379*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = device_get_softc(dev);
380*d6b3aaf8SOleksandr Tymoshenko 	int i;
381*d6b3aaf8SOleksandr Tymoshenko 
382*d6b3aaf8SOleksandr Tymoshenko 	for (i = 0; i < sc->num_slots; i++)
383*d6b3aaf8SOleksandr Tymoshenko 		sdhci_generic_resume(&sc->slots[i]);
384*d6b3aaf8SOleksandr Tymoshenko 	return (bus_generic_resume(dev));
385*d6b3aaf8SOleksandr Tymoshenko }
386*d6b3aaf8SOleksandr Tymoshenko 
387*d6b3aaf8SOleksandr Tymoshenko 
388*d6b3aaf8SOleksandr Tymoshenko static void
389*d6b3aaf8SOleksandr Tymoshenko sdhci_pci_intr(void *arg)
390*d6b3aaf8SOleksandr Tymoshenko {
391*d6b3aaf8SOleksandr Tymoshenko 	struct sdhci_pci_softc *sc = (struct sdhci_pci_softc *)arg;
392*d6b3aaf8SOleksandr Tymoshenko 	int i;
393*d6b3aaf8SOleksandr Tymoshenko 
394*d6b3aaf8SOleksandr Tymoshenko 	for (i = 0; i < sc->num_slots; i++) {
395*d6b3aaf8SOleksandr Tymoshenko 		struct sdhci_slot *slot = &sc->slots[i];
396*d6b3aaf8SOleksandr Tymoshenko 		sdhci_generic_intr(slot);
397*d6b3aaf8SOleksandr Tymoshenko 	}
398*d6b3aaf8SOleksandr Tymoshenko }
399*d6b3aaf8SOleksandr Tymoshenko 
400*d6b3aaf8SOleksandr Tymoshenko static device_method_t sdhci_methods[] = {
401*d6b3aaf8SOleksandr Tymoshenko 	/* device_if */
402*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(device_probe, sdhci_pci_probe),
403*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(device_attach, sdhci_pci_attach),
404*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(device_detach, sdhci_pci_detach),
405*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(device_suspend, sdhci_pci_suspend),
406*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(device_resume, sdhci_pci_resume),
407*d6b3aaf8SOleksandr Tymoshenko 
408*d6b3aaf8SOleksandr Tymoshenko 	/* Bus interface */
409*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
410*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
411*d6b3aaf8SOleksandr Tymoshenko 
412*d6b3aaf8SOleksandr Tymoshenko 	/* mmcbr_if */
413*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios),
414*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_request, sdhci_generic_request),
415*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro),
416*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host),
417*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host),
418*d6b3aaf8SOleksandr Tymoshenko 
419*d6b3aaf8SOleksandr Tymoshenko 	/* SDHCI registers accessors */
420*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(sdhci_read_1,		sdhci_pci_read_1),
421*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(sdhci_read_2,		sdhci_pci_read_2),
422*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(sdhci_read_4,		sdhci_pci_read_4),
423*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(sdhci_read_multi_4,	sdhci_pci_read_multi_4),
424*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(sdhci_write_1,	sdhci_pci_write_1),
425*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(sdhci_write_2,	sdhci_pci_write_2),
426*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(sdhci_write_4,	sdhci_pci_write_4),
427*d6b3aaf8SOleksandr Tymoshenko 	DEVMETHOD(sdhci_write_multi_4,	sdhci_pci_write_multi_4),
428*d6b3aaf8SOleksandr Tymoshenko 
429*d6b3aaf8SOleksandr Tymoshenko 	{0, 0},
430*d6b3aaf8SOleksandr Tymoshenko };
431*d6b3aaf8SOleksandr Tymoshenko 
432*d6b3aaf8SOleksandr Tymoshenko static driver_t sdhci_pci_driver = {
433*d6b3aaf8SOleksandr Tymoshenko 	"sdhci_pci",
434*d6b3aaf8SOleksandr Tymoshenko 	sdhci_methods,
435*d6b3aaf8SOleksandr Tymoshenko 	sizeof(struct sdhci_pci_softc),
436*d6b3aaf8SOleksandr Tymoshenko };
437*d6b3aaf8SOleksandr Tymoshenko static devclass_t sdhci_pci_devclass;
438*d6b3aaf8SOleksandr Tymoshenko 
439*d6b3aaf8SOleksandr Tymoshenko DRIVER_MODULE(sdhci_pci, pci, sdhci_pci_driver, sdhci_pci_devclass, 0, 0);
440*d6b3aaf8SOleksandr Tymoshenko MODULE_DEPEND(sdhci_pci, sdhci, 1, 1, 1);
441