1 /* $OpenBSD: puc_cardbus.c,v 1.9 2022/04/06 18:59:28 naddy Exp $ */
2
3 /*
4 * Copyright (c) 2006 Michael Shalayeff
5 * All rights reserved.
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 MIND, USE, DATA OR PROFITS, WHETHER IN
16 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/device.h>
23 #include <sys/tty.h>
24
25 #include <machine/bus.h>
26 #include <dev/ic/comvar.h>
27
28 #include <dev/pci/pcireg.h>
29 #include <dev/pci/pcivar.h>
30 #include <dev/pci/pcidevs.h>
31 #include <dev/cardbus/cardbusvar.h>
32
33 #include <dev/pci/pucvar.h>
34
35 struct puc_cardbus_softc {
36 struct puc_softc sc_psc;
37
38 struct cardbus_devfunc *ct;
39 int intrline;
40 };
41
42 int puc_cardbus_match(struct device *, void *, void *);
43 void puc_cardbus_attach(struct device *, struct device *, void *);
44 int puc_cardbus_detach(struct device *, int);
45
46 const char *puc_cardbus_intr_string(struct puc_attach_args *);
47 void *puc_cardbus_intr_establish(struct puc_attach_args *, int,
48 int (*)(void *), void *, char *);
49
50 const struct cfattach puc_cardbus_ca = {
51 sizeof(struct puc_cardbus_softc), puc_cardbus_match,
52 puc_cardbus_attach, puc_cardbus_detach
53 };
54
55 int
56 puc_cardbus_match(struct device *parent, void *match, void *aux)
57 {
58 struct cardbus_attach_args *ca = aux;
59 pci_chipset_tag_t pc = ca->ca_pc;
60 pcireg_t bhlc, reg;
61
62 bhlc = pci_conf_read(pc, ca->ca_tag, PCI_BHLC_REG);
63 if (PCI_HDRTYPE_TYPE(bhlc) != 0)
64 return(0);
65
66 /* this one is some sort of a bridge and not a puc */
67 if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_OXFORD2 &&
68 PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_OXFORD2_EXSYS_EX41098)
69 return (0);
70
71 reg = pci_conf_read(pc, ca->ca_tag, PCI_SUBSYS_ID_REG);
72 if (puc_find_description(PCI_VENDOR(ca->ca_id),
73 PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg)))
74 return (10);
75
76 return (0);
77 }
78
79 void
80 puc_cardbus_attach(struct device *parent, struct device *self, void *aux)
81 {
82 struct puc_cardbus_softc *csc = (struct puc_cardbus_softc *)self;
83 struct puc_softc *sc = &csc->sc_psc;
84 struct cardbus_attach_args *ca = aux;
85 struct cardbus_devfunc *ct = ca->ca_ct;
86 cardbus_chipset_tag_t cc = ct->ct_cc;
87 pci_chipset_tag_t pc = ca->ca_pc;
88 cardbus_function_tag_t cf = ct->ct_cf;
89 struct puc_attach_args paa;
90 pcireg_t reg;
91 int i;
92
93 Cardbus_function_enable(ct);
94
95 csc->ct = ct;
96
97 reg = pci_conf_read(pc, ca->ca_tag, PCI_SUBSYS_ID_REG);
98 sc->sc_desc = puc_find_description(PCI_VENDOR(ca->ca_id),
99 PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg));
100
101 puc_print_ports(sc->sc_desc);
102
103 /* the fifth one is some memory we dunno */
104 for (i = 0; i < PUC_NBARS; i++) {
105 pcireg_t type;
106 int bar;
107
108 sc->sc_bar_mappings[i].mapped = 0;
109 bar = PCI_MAPREG_START + 4 * i;
110 if (!pci_mapreg_probe(pc, ca->ca_tag, bar, &type))
111 continue;
112
113 if (!(sc->sc_bar_mappings[i].mapped = !Cardbus_mapreg_map(ct,
114 bar, type, 0,
115 &sc->sc_bar_mappings[i].t, &sc->sc_bar_mappings[i].h,
116 &sc->sc_bar_mappings[i].a, &sc->sc_bar_mappings[i].s)))
117 printf("%s: couldn't map BAR at offset 0x%lx\n",
118 sc->sc_dev.dv_xname, (long)bar);
119 sc->sc_bar_mappings[i].type = type;
120 }
121
122 csc->intrline = ca->ca_intrline;
123
124 if (pci_get_capability(pc, ca->ca_tag, PCI_CAP_PWRMGMT, ®,
125 0)) {
126 reg = pci_conf_read(pc, ca->ca_tag, reg + 4) & 3;
127 if (reg) {
128 printf("%s: awakening from state D%d\n",
129 sc->sc_dev.dv_xname, reg);
130 pci_conf_write(pc, ca->ca_tag, reg + 4, 0);
131 }
132 }
133
134 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
135 (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE);
136 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
137
138 paa.puc = sc;
139 paa.intr_string = &puc_cardbus_intr_string;
140 paa.intr_establish = &puc_cardbus_intr_establish;
141
142 puc_common_attach(sc, &paa);
143 }
144
145 const char *
146 puc_cardbus_intr_string(struct puc_attach_args *paa)
147 {
148 struct puc_cardbus_softc *sc = paa->puc;
149 static char str[16];
150
151 snprintf(str, sizeof str, "irq %d", sc->intrline);
152 return (str);
153 }
154
155 void *
156 puc_cardbus_intr_establish(struct puc_attach_args *paa, int type,
157 int (*func)(void *), void *arg, char *name)
158 {
159 struct puc_cardbus_softc *sc = paa->puc;
160 struct puc_softc *psc = &sc->sc_psc;
161 struct cardbus_devfunc *ct = sc->ct;
162
163 psc->sc_ports[paa->port].intrhand =
164 cardbus_intr_establish(ct->ct_cc, ct->ct_cf, sc->intrline,
165 type, func, arg, name);
166
167 return (psc->sc_ports[paa->port].intrhand);
168 }
169
170 int
171 puc_cardbus_detach(struct device *self, int flags)
172 {
173 struct puc_cardbus_softc *sc = (struct puc_cardbus_softc *)self;
174 struct puc_softc *psc = &sc->sc_psc;
175 struct cardbus_devfunc *ct = sc->ct;
176 int i, rv;
177
178 for (i = PUC_MAX_PORTS; i--; ) {
179 if (psc->sc_ports[i].intrhand)
180 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf,
181 psc->sc_ports[i].intrhand);
182 if (psc->sc_ports[i].dev)
183 if ((rv = config_detach(psc->sc_ports[i].dev, flags)))
184 return (rv);
185 }
186
187 for (i = PUC_NBARS; i--; )
188 if (psc->sc_bar_mappings[i].mapped)
189 Cardbus_mapreg_unmap(ct, psc->sc_bar_mappings[i].type,
190 psc->sc_bar_mappings[i].t,
191 psc->sc_bar_mappings[i].h,
192 psc->sc_bar_mappings[i].s);
193
194 return (0);
195 }
Cache object: 9ae4ce2c684925dad6ca969b78692464
|