xref: /openbsd/sys/dev/cardbus/puc_cardbus.c (revision 09467b48)
1 /*	$OpenBSD: puc_cardbus.c,v 1.8 2011/11/15 22:27:53 deraadt 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 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, &reg,
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 }
196