xref: /netbsd-src/sys/dev/pci/sdhc_pci.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1 /*	$NetBSD: sdhc_pci.c,v 1.9 2012/07/29 23:14:13 matt Exp $	*/
2 /*	$OpenBSD: sdhc_pci.c,v 1.7 2007/10/30 18:13:45 chl Exp $	*/
3 
4 /*
5  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: sdhc_pci.c,v 1.9 2012/07/29 23:14:13 matt Exp $");
22 
23 #ifdef _KERNEL_OPT
24 #include "opt_sdmmc.h"
25 #endif
26 
27 #include <sys/param.h>
28 #include <sys/device.h>
29 #include <sys/systm.h>
30 #include <sys/malloc.h>
31 #include <sys/pmf.h>
32 
33 #include <dev/pci/pcivar.h>
34 #include <dev/pci/pcidevs.h>
35 
36 #include <dev/sdmmc/sdhcreg.h>
37 #include <dev/sdmmc/sdhcvar.h>
38 #include <dev/sdmmc/sdmmcvar.h>
39 
40 /* PCI base address registers */
41 #define SDHC_PCI_BAR_START		PCI_MAPREG_START
42 #define SDHC_PCI_BAR_END		PCI_MAPREG_END
43 
44 /* PCI interface classes */
45 #define SDHC_PCI_INTERFACE_NO_DMA	0x00
46 #define SDHC_PCI_INTERFACE_DMA		0x01
47 #define SDHC_PCI_INTERFACE_VENDOR	0x02
48 
49 /*
50  * 8-bit PCI configuration register that tells us how many slots there
51  * are and which BAR entry corresponds to the first slot.
52  */
53 #define SDHC_PCI_CONF_SLOT_INFO		0x40
54 #define SDHC_PCI_NUM_SLOTS(info)	((((info) >> 4) & 0x7) + 1)
55 #define SDHC_PCI_FIRST_BAR(info)	((info) & 0x7)
56 
57 struct sdhc_pci_softc {
58 	struct sdhc_softc sc;
59 	void *sc_ih;
60 };
61 
62 static int sdhc_pci_match(device_t, cfdata_t, void *);
63 static void sdhc_pci_attach(device_t, device_t, void *);
64 
65 CFATTACH_DECL_NEW(sdhc_pci, sizeof(struct sdhc_pci_softc),
66     sdhc_pci_match, sdhc_pci_attach, NULL, NULL);
67 
68 #ifdef SDHC_DEBUG
69 #define	DPRINTF(s)	printf s
70 #else
71 #define	DPRINTF(s)	/**/
72 #endif
73 
74 static const struct sdhc_pci_quirk {
75 	pci_vendor_id_t		vendor;
76 	pci_product_id_t	product;
77 	pci_vendor_id_t		subvendor;
78 	pci_product_id_t	subproduct;
79 	u_int			function;
80 
81 	uint32_t		flags;
82 #define	SDHC_PCI_QUIRK_FORCE_DMA		(1U << 0)
83 #define	SDHC_PCI_QUIRK_TI_HACK			(1U << 1)
84 #define	SDHC_PCI_QUIRK_NO_PWR0			(1U << 2)
85 #define	SDHC_PCI_QUIRK_RICOH_LOWER_FREQ_HACK	(1U << 3)
86 } sdhc_pci_quirk_table[] = {
87 	{
88 		PCI_VENDOR_TI,
89 		PCI_PRODUCT_TI_PCI72111SD,
90 		0xffff,
91 		0xffff,
92 		4,
93 		SDHC_PCI_QUIRK_TI_HACK
94 	},
95 
96 	{
97 		PCI_VENDOR_TI,
98 		PCI_PRODUCT_TI_PCIXX12SD,
99 		0xffff,
100 		0xffff,
101 		3,
102 		SDHC_PCI_QUIRK_TI_HACK
103 	},
104 
105 	{
106 		PCI_VENDOR_ENE,
107 		PCI_PRODUCT_ENE_CB712,
108 		0xffff,
109 		0xffff,
110 		0,
111 		SDHC_PCI_QUIRK_NO_PWR0
112 	},
113 
114 	{
115 		PCI_VENDOR_RICOH,
116 		PCI_PRODUCT_RICOH_Rx5U823,
117 		0xffff,
118 		0xffff,
119 		0,
120 		SDHC_PCI_QUIRK_RICOH_LOWER_FREQ_HACK
121 	},
122 
123 	{
124 		PCI_VENDOR_RICOH,
125 		PCI_PRODUCT_RICOH_Rx5C822,
126 		0xffff,
127 		0xffff,
128 		~0,
129 		SDHC_PCI_QUIRK_FORCE_DMA
130 	},
131 
132 	{
133 		PCI_VENDOR_RICOH,
134 		PCI_PRODUCT_RICOH_Rx5U822,
135 		0xffff,
136 		0xffff,
137 		~0,
138 		SDHC_PCI_QUIRK_FORCE_DMA
139 	},
140 };
141 
142 static void sdhc_pci_quirk_ti_hack(struct pci_attach_args *);
143 static void sdhc_pci_quirk_ricoh_lower_freq_hack(struct pci_attach_args *);
144 
145 static uint32_t
146 sdhc_pci_lookup_quirk_flags(struct pci_attach_args *pa)
147 {
148 	const struct sdhc_pci_quirk *q;
149 	pcireg_t id;
150 	pci_vendor_id_t vendor;
151 	pci_product_id_t product;
152 	int i;
153 
154 	for (i = 0; i < __arraycount(sdhc_pci_quirk_table); i++) {
155 		q = &sdhc_pci_quirk_table[i];
156 
157 		if ((PCI_VENDOR(pa->pa_id) == q->vendor)
158 		 && (PCI_PRODUCT(pa->pa_id) == q->product)) {
159 			if ((q->function != ~0)
160 			 && (pa->pa_function != q->function))
161 				continue;
162 
163 			if ((q->subvendor == 0xffff)
164 			 && (q->subproduct == 0xffff))
165 				return (q->flags);
166 
167 			id = pci_conf_read(pa->pa_pc, pa->pa_tag,
168 			    PCI_SUBSYS_ID_REG);
169 			vendor = PCI_VENDOR(id);
170 			product = PCI_PRODUCT(id);
171 
172 			if ((q->subvendor != 0xffff)
173 			 && (q->subproduct != 0xffff)) {
174 				if ((vendor == q->subvendor)
175 				 && (product == q->subproduct))
176 					return (q->flags);
177 			} else if (q->subvendor != 0xffff) {
178 				if (product == q->subproduct)
179 					return (q->flags);
180 			} else {
181 				if (vendor == q->subvendor)
182 					return (q->flags);
183 			}
184 		}
185 	}
186 	return (0);
187 }
188 
189 static int
190 sdhc_pci_match(device_t parent, cfdata_t cf, void *aux)
191 {
192 	struct pci_attach_args *pa = aux;
193 
194 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SYSTEM &&
195 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SYSTEM_SDHC)
196 		return (1);
197 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RICOH &&
198 	    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_Rx5U822 ||
199 	     PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_Rx5U823))
200 		return (1);
201 	return (0);
202 }
203 
204 static void
205 sdhc_pci_attach(device_t parent, device_t self, void *aux)
206 {
207 	struct sdhc_pci_softc *sc = device_private(self);
208 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
209 	pci_chipset_tag_t pc = pa->pa_pc;
210 	pcitag_t tag = pa->pa_tag;
211 	pci_intr_handle_t ih;
212 	pcireg_t csr;
213 	pcireg_t slotinfo;
214 	char const *intrstr;
215 	int nslots;
216 	int reg;
217 	int cnt;
218 	bus_space_tag_t iot;
219 	bus_space_handle_t ioh;
220 	bus_size_t size;
221 	uint32_t flags;
222 
223 	sc->sc.sc_dev = self;
224 	sc->sc.sc_dmat = pa->pa_dmat;
225 	sc->sc.sc_host = NULL;
226 
227 	pci_aprint_devinfo(pa, NULL);
228 
229 	/* Some controllers needs special treatment. */
230 	flags = sdhc_pci_lookup_quirk_flags(pa);
231 	if (ISSET(flags, SDHC_PCI_QUIRK_TI_HACK))
232 		sdhc_pci_quirk_ti_hack(pa);
233 	if (ISSET(flags, SDHC_PCI_QUIRK_FORCE_DMA))
234 		SET(sc->sc.sc_flags, SDHC_FLAG_FORCE_DMA);
235 	if (ISSET(flags, SDHC_PCI_QUIRK_NO_PWR0))
236 		SET(sc->sc.sc_flags, SDHC_FLAG_NO_PWR0);
237 	if (ISSET(flags, SDHC_PCI_QUIRK_RICOH_LOWER_FREQ_HACK))
238 		sdhc_pci_quirk_ricoh_lower_freq_hack(pa);
239 
240 	/*
241 	 * Map and attach all hosts supported by the host controller.
242 	 */
243 	slotinfo = pci_conf_read(pc, tag, SDHC_PCI_CONF_SLOT_INFO);
244 	nslots = SDHC_PCI_NUM_SLOTS(slotinfo);
245 
246 	/* Allocate an array big enough to hold all the possible hosts */
247 	sc->sc.sc_host = malloc(sizeof(struct sdhc_host *) * nslots,
248 	    M_DEVBUF, M_NOWAIT | M_ZERO);
249 	if (sc->sc.sc_host == NULL) {
250 		aprint_error_dev(self, "couldn't alloc memory\n");
251 		goto err;
252 	}
253 
254 	/* Enable the device. */
255 	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
256 	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
257 		       csr | PCI_COMMAND_MASTER_ENABLE);
258 
259 	/* Map and establish the interrupt. */
260 	if (pci_intr_map(pa, &ih)) {
261 		aprint_error_dev(self, "couldn't map interrupt\n");
262 		goto err;
263 	}
264 
265 	intrstr = pci_intr_string(pc, ih);
266 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_SDMMC, sdhc_intr, &sc->sc);
267 	if (sc->sc_ih == NULL) {
268 		aprint_error_dev(self, "couldn't establish interrupt\n");
269 		goto err;
270 	}
271 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
272 
273 	/* Enable use of DMA if supported by the interface. */
274 	if ((PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA))
275 		SET(sc->sc.sc_flags, SDHC_FLAG_USE_DMA);
276 
277 	/* XXX: handle 64-bit BARs */
278 	cnt = 0;
279 	for (reg = SDHC_PCI_BAR_START + SDHC_PCI_FIRST_BAR(slotinfo) *
280 		 sizeof(uint32_t);
281 	     reg < SDHC_PCI_BAR_END && nslots > 0;
282 	     reg += sizeof(uint32_t), nslots--) {
283 		if (pci_mapreg_map(pa, reg, PCI_MAPREG_TYPE_MEM, 0,
284 		    &iot, &ioh, NULL, &size)) {
285 			continue;
286 		}
287 
288 		cnt++;
289 		if (sdhc_host_found(&sc->sc, iot, ioh, size) != 0) {
290 			/* XXX: sc->sc_host leak */
291 			aprint_error_dev(self,
292 			    "couldn't initialize host (0x%x)\n", reg);
293 		}
294 	}
295 	if (cnt == 0) {
296 		aprint_error_dev(self, "couldn't map register\n");
297 		goto err;
298 	}
299 
300 	if (!pmf_device_register1(self, sdhc_suspend, sdhc_resume,
301 	    sdhc_shutdown)) {
302 		aprint_error_dev(self, "couldn't establish powerhook\n");
303 	}
304 
305 	return;
306 
307 err:
308 	if (sc->sc.sc_host != NULL)
309 		free(sc->sc.sc_host, M_DEVBUF);
310 }
311 
312 static void
313 sdhc_pci_conf_write(struct pci_attach_args *pa, int reg, uint8_t val)
314 {
315 	pcireg_t r;
316 
317 	r = pci_conf_read(pa->pa_pc, pa->pa_tag, reg & ~0x3);
318 	r &= ~(0xff << ((reg & 0x3) * 8));
319 	r |= (val << ((reg & 0x3) * 8));
320 	pci_conf_write(pa->pa_pc, pa->pa_tag, reg & ~0x3, r);
321 }
322 
323 /* TI specific register */
324 #define SDHC_PCI_GENERAL_CTL		0x4c
325 #define  MMC_SD_DIS			0x02
326 
327 static void
328 sdhc_pci_quirk_ti_hack(struct pci_attach_args *pa)
329 {
330 	pci_chipset_tag_t pc = pa->pa_pc;
331 	pcitag_t tag;
332 	pcireg_t id, reg;
333 
334 	/* Look at func - 1 for the flash device */
335 	tag = pci_make_tag(pc, pa->pa_bus, pa->pa_device, pa->pa_function - 1);
336 	id = pci_conf_read(pc, tag, PCI_ID_REG);
337 	if (PCI_VENDOR(id) != PCI_VENDOR_TI) {
338 		return;
339 	}
340 	switch (PCI_PRODUCT(id)) {
341 	case PCI_PRODUCT_TI_PCI72111FM:
342 	case PCI_PRODUCT_TI_PCIXX12FM:
343 		break;
344 	default:
345 		return;
346 	}
347 
348 	/*
349 	 * Disable MMC/SD on the flash media controller so the
350 	 * SD host takes over.
351 	 */
352 	reg = pci_conf_read(pc, tag, SDHC_PCI_GENERAL_CTL);
353 	reg |= MMC_SD_DIS;
354 	pci_conf_write(pc, tag, SDHC_PCI_GENERAL_CTL, reg);
355 }
356 
357 /* Ricoh specific register */
358 #define SDHC_PCI_MODE_KEY		0xf9
359 #define SDHC_PCI_MODE			0x150
360 #define  SDHC_PCI_MODE_SD20		0x10
361 #define SDHC_PCI_BASE_FREQ_KEY		0xfc
362 #define SDHC_PCI_BASE_FREQ		0xe1
363 
364 /* Some RICOH controllers need to be bumped into the right mode. */
365 static void
366 sdhc_pci_quirk_ricoh_lower_freq_hack(struct pci_attach_args *pa)
367 {
368 
369 	/* Enable SD2.0 mode. */
370 	sdhc_pci_conf_write(pa, SDHC_PCI_MODE_KEY, 0xfc);
371 	sdhc_pci_conf_write(pa, SDHC_PCI_MODE, SDHC_PCI_MODE_SD20);
372 	sdhc_pci_conf_write(pa, SDHC_PCI_MODE_KEY, 0x00);
373 
374 	/*
375 	 * Some SD/MMC cards don't work with the default base
376 	 * clock frequency of 200MHz.  Lower it to 50Hz.
377 	 */
378 	sdhc_pci_conf_write(pa, SDHC_PCI_BASE_FREQ_KEY, 0x01);
379 	sdhc_pci_conf_write(pa, SDHC_PCI_BASE_FREQ, 50);
380 	sdhc_pci_conf_write(pa, SDHC_PCI_BASE_FREQ_KEY, 0x00);
381 }
382