xref: /netbsd-src/sys/dev/pci/rtsx_pci.c (revision 6cf6fe02a981b55727c49c3d37b0d8191a98c0ee)
1 /*	$NetBSD: rtsx_pci.c,v 1.2 2014/03/29 19:28:25 christos Exp $	*/
2 /*	$OpenBSD: rtsx_pci.c,v 1.4 2013/11/06 13:51:02 stsp Exp $	*/
3 
4 /*
5  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
6  * Copyright (c) 2012 Stefan Sperling <stsp@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/cdefs.h>
22 __KERNEL_RCSID(0, "$NetBSD: rtsx_pci.c,v 1.2 2014/03/29 19:28:25 christos Exp $");
23 
24 #include <sys/param.h>
25 #include <sys/device.h>
26 #include <sys/systm.h>
27 #include <sys/malloc.h>
28 #include <sys/pmf.h>
29 
30 #include <dev/pci/pcivar.h>
31 #include <dev/pci/pcidevs.h>
32 
33 #include <dev/ic/rtsxreg.h>
34 #include <dev/ic/rtsxvar.h>
35 
36 #include <dev/sdmmc/sdmmcvar.h>
37 
38 #define RTSX_PCI_BAR	0x10
39 
40 struct rtsx_pci_softc {
41 	struct rtsx_softc sc;
42 	pci_chipset_tag_t sc_pc;
43 	void *sc_ih;
44 };
45 
46 static int rtsx_pci_match(device_t , cfdata_t, void *);
47 static void rtsx_pci_attach(device_t, device_t, void *);
48 static int rtsx_pci_detach(device_t, int);
49 
50 CFATTACH_DECL_NEW(rtsx_pci, sizeof(struct rtsx_pci_softc),
51     rtsx_pci_match, rtsx_pci_attach, rtsx_pci_detach, NULL);
52 
53 #ifdef RTSX_DEBUG
54 extern int rtsxdebug;
55 #define DPRINTF(n,s)	do { if ((n) <= rtsxdebug) printf s; } while (0)
56 #else
57 #define DPRINTF(n,s)	/**/
58 #endif
59 
60 static int
61 rtsx_pci_match(device_t parent, cfdata_t cf, void *aux)
62 {
63 	struct pci_attach_args *pa = aux;
64 
65 	/*
66 	 * Explicitly match the UNDEFINED device class only. Some RTS5902
67 	 * devices advertise a SYSTEM/SDHC class in addition to the UNDEFINED
68 	 * device class. Let sdhc(4) handle the SYSTEM/SDHC ones.
69 	 */
70 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_REALTEK ||
71 	    PCI_CLASS(pa->pa_class) != PCI_CLASS_UNDEFINED)
72 		return 0;
73 
74 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_REALTEK_RTS5209 ||
75 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_REALTEK_RTS5229)
76 		return 1;
77 
78 	return 0;
79 }
80 
81 static void
82 rtsx_pci_attach(device_t parent, device_t self, void *aux)
83 {
84 	struct rtsx_pci_softc *sc = device_private(self);
85 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
86 	pci_chipset_tag_t pc = pa->pa_pc;
87 	pcitag_t tag = pa->pa_tag;
88 	pci_intr_handle_t ih;
89 	pcireg_t reg;
90 	char const *intrstr;
91 	bus_space_tag_t iot;
92 	bus_space_handle_t ioh;
93 	bus_size_t size;
94 	uint32_t flags;
95 	char intrbuf[PCI_INTRSTR_LEN];
96 
97 	sc->sc.sc_dev = self;
98 	sc->sc_pc = pc;
99 
100 	pci_aprint_devinfo(pa, NULL);
101 
102 	if ((pci_conf_read(pc, tag, RTSX_CFG_PCI) & RTSX_CFG_ASIC) != 0) {
103 		aprint_error_dev(self, "no asic\n");
104 		return;
105 	}
106 
107 	if (pci_mapreg_map(pa, RTSX_PCI_BAR, PCI_MAPREG_TYPE_MEM, 0,
108 	    &iot, &ioh, NULL, &size)) {
109 		aprint_error_dev(self, "couldn't map registers\n");
110 		return;
111 	}
112 
113 	if (pci_intr_map(pa, &ih)) {
114 		aprint_error_dev(self, "couldn't map interrupt\n");
115 		return;
116 	}
117 	intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
118 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_SDMMC, rtsx_intr, &sc->sc);
119 	if (sc->sc_ih == NULL) {
120 		aprint_error_dev(self, "couldn't establish interrupt\n");
121 		return;
122 	}
123 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
124 
125 	/* Enable the device */
126 	reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
127 	reg |= PCI_COMMAND_MASTER_ENABLE;
128 	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg);
129 
130 	/* Power up the device */
131 	pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0);
132 
133 	switch (PCI_PRODUCT(pa->pa_id)) {
134 	case PCI_PRODUCT_REALTEK_RTS5209:
135 		flags = RTSX_F_5209;
136 		break;
137 	case PCI_PRODUCT_REALTEK_RTS5229:
138 	default:
139 		flags = RTSX_F_5229;
140 		break;
141 	}
142 
143 	if (rtsx_attach(&sc->sc, iot, ioh, size, pa->pa_dmat, flags) != 0) {
144 		aprint_error_dev(self, "couldn't initialize chip\n");
145 		return;
146 	}
147 
148 	if (!pmf_device_register1(self, rtsx_suspend, rtsx_resume,
149 	    rtsx_shutdown))
150 		aprint_error_dev(self, "couldn't establish powerhook\n");
151 }
152 
153 static int
154 rtsx_pci_detach(device_t self, int flags)
155 {
156 	struct rtsx_pci_softc *sc = device_private(self);
157 	int rv;
158 
159 	rv = rtsx_detach(&sc->sc, flags);
160 	if (rv)
161 		return rv;
162 
163 	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
164 
165 	return 0;
166 }
167