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