xref: /openbsd/sys/dev/cardbus/puc_cardbus.c (revision c7101648)
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, &reg,
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