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