xref: /openbsd/sys/dev/cardbus/puc_cardbus.c (revision c7101648)
1*c7101648Sjsg /*	$OpenBSD: puc_cardbus.c,v 1.10 2024/05/24 06:26:47 jsg Exp $	*/
2ad365a85Smickey 
3ad365a85Smickey /*
4ad365a85Smickey  * Copyright (c) 2006 Michael Shalayeff
5ad365a85Smickey  * All rights reserved.
6ad365a85Smickey  *
7ad365a85Smickey  * Permission to use, copy, modify, and distribute this software for any
8ad365a85Smickey  * purpose with or without fee is hereby granted, provided that the above
9ad365a85Smickey  * copyright notice and this permission notice appear in all copies.
10ad365a85Smickey  *
11ad365a85Smickey  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12ad365a85Smickey  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13ad365a85Smickey  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14ad365a85Smickey  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15ad365a85Smickey  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
16ad365a85Smickey  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17ad365a85Smickey  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18ad365a85Smickey  */
19ad365a85Smickey 
20ad365a85Smickey #include <sys/param.h>
21ad365a85Smickey #include <sys/systm.h>
22ad365a85Smickey #include <sys/device.h>
23ad365a85Smickey 
24ad365a85Smickey #include <dev/pci/pcireg.h>
25ad365a85Smickey #include <dev/pci/pcivar.h>
26ad365a85Smickey #include <dev/pci/pcidevs.h>
27ad365a85Smickey #include <dev/cardbus/cardbusvar.h>
28ad365a85Smickey 
29ad365a85Smickey #include <dev/pci/pucvar.h>
30ad365a85Smickey 
31ad365a85Smickey struct puc_cardbus_softc {
32ad365a85Smickey 	struct puc_softc sc_psc;
33ad365a85Smickey 
34ad365a85Smickey 	struct cardbus_devfunc *ct;
35ad365a85Smickey 	int intrline;
36ad365a85Smickey };
37ad365a85Smickey 
38ad365a85Smickey int	puc_cardbus_match(struct device *, void *, void *);
39ad365a85Smickey void	puc_cardbus_attach(struct device *, struct device *, void *);
40ad365a85Smickey int	puc_cardbus_detach(struct device *, int);
41ad365a85Smickey 
42ad365a85Smickey const char *puc_cardbus_intr_string(struct puc_attach_args *);
43ad365a85Smickey void *puc_cardbus_intr_establish(struct puc_attach_args *, int,
44ad365a85Smickey     int (*)(void *), void *, char *);
45ad365a85Smickey 
46471aeecfSnaddy const struct cfattach puc_cardbus_ca = {
47ad365a85Smickey 	sizeof(struct puc_cardbus_softc), puc_cardbus_match,
48ad365a85Smickey 	puc_cardbus_attach, puc_cardbus_detach
49ad365a85Smickey };
50ad365a85Smickey 
51ad365a85Smickey int
puc_cardbus_match(struct device * parent,void * match,void * aux)52ad365a85Smickey puc_cardbus_match(struct device *parent, void *match, void *aux)
53ad365a85Smickey {
54ad365a85Smickey 	struct cardbus_attach_args *ca = aux;
55c80ce954Sjsg 	pci_chipset_tag_t pc = ca->ca_pc;
56401cfd38Sjsg 	pcireg_t bhlc, reg;
57ad365a85Smickey 
58c80ce954Sjsg 	bhlc = pci_conf_read(pc, ca->ca_tag, PCI_BHLC_REG);
59ad365a85Smickey 	if (PCI_HDRTYPE_TYPE(bhlc) != 0)
60ad365a85Smickey 		return(0);
61ad365a85Smickey 
62ad365a85Smickey 	/* this one is some sort of a bridge and not a puc */
63ad365a85Smickey 	if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_OXFORD2 &&
64ad365a85Smickey 	    PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_OXFORD2_EXSYS_EX41098)
65ad365a85Smickey 		return (0);
66ad365a85Smickey 
67c80ce954Sjsg 	reg = pci_conf_read(pc, ca->ca_tag, PCI_SUBSYS_ID_REG);
68ad365a85Smickey 	if (puc_find_description(PCI_VENDOR(ca->ca_id),
69ad365a85Smickey 	    PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg)))
70ad365a85Smickey 		return (10);
71ad365a85Smickey 
72ad365a85Smickey 	return (0);
73ad365a85Smickey }
74ad365a85Smickey 
75ad365a85Smickey void
puc_cardbus_attach(struct device * parent,struct device * self,void * aux)76ad365a85Smickey puc_cardbus_attach(struct device *parent, struct device *self, void *aux)
77ad365a85Smickey {
78ad365a85Smickey 	struct puc_cardbus_softc *csc = (struct puc_cardbus_softc *)self;
79ad365a85Smickey 	struct puc_softc *sc = &csc->sc_psc;
80ad365a85Smickey 	struct cardbus_attach_args *ca = aux;
81ad365a85Smickey 	struct cardbus_devfunc *ct = ca->ca_ct;
82d38c70dfSjsg 	cardbus_chipset_tag_t cc = ct->ct_cc;
83c80ce954Sjsg 	pci_chipset_tag_t pc = ca->ca_pc;
84ad365a85Smickey 	cardbus_function_tag_t cf = ct->ct_cf;
85ad365a85Smickey 	struct puc_attach_args paa;
86401cfd38Sjsg 	pcireg_t reg;
87ad365a85Smickey 	int i;
88ad365a85Smickey 
89ad365a85Smickey 	Cardbus_function_enable(ct);
90ad365a85Smickey 
91ad365a85Smickey 	csc->ct = ct;
92ad365a85Smickey 
93c80ce954Sjsg 	reg = pci_conf_read(pc, ca->ca_tag, PCI_SUBSYS_ID_REG);
94ad365a85Smickey 	sc->sc_desc = puc_find_description(PCI_VENDOR(ca->ca_id),
95ad365a85Smickey 	    PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg));
96ad365a85Smickey 
97ad365a85Smickey 	puc_print_ports(sc->sc_desc);
98ad365a85Smickey 
99ad365a85Smickey 	/* the fifth one is some memory we dunno */
100ad365a85Smickey 	for (i = 0; i < PUC_NBARS; i++) {
101401cfd38Sjsg 		pcireg_t type;
102ad365a85Smickey 		int bar;
103ad365a85Smickey 
104ad365a85Smickey 		sc->sc_bar_mappings[i].mapped = 0;
105ad365a85Smickey 		bar = PCI_MAPREG_START + 4 * i;
106e6afa982Sjsg 		if (!pci_mapreg_probe(pc, ca->ca_tag, bar, &type))
107ad365a85Smickey 			continue;
108ad365a85Smickey 
109ad365a85Smickey 		if (!(sc->sc_bar_mappings[i].mapped = !Cardbus_mapreg_map(ct,
110ad365a85Smickey 		    bar, type, 0,
111ad365a85Smickey 		    &sc->sc_bar_mappings[i].t, &sc->sc_bar_mappings[i].h,
112ad365a85Smickey 		    &sc->sc_bar_mappings[i].a, &sc->sc_bar_mappings[i].s)))
113ad365a85Smickey 			printf("%s: couldn't map BAR at offset 0x%lx\n",
114ad365a85Smickey 			    sc->sc_dev.dv_xname, (long)bar);
115ad365a85Smickey 		sc->sc_bar_mappings[i].type = type;
116ad365a85Smickey 	}
117ad365a85Smickey 
118ad365a85Smickey 	csc->intrline = ca->ca_intrline;
119ad365a85Smickey 
120c80ce954Sjsg 	if (pci_get_capability(pc, ca->ca_tag, PCI_CAP_PWRMGMT, &reg,
121ad365a85Smickey 	    0)) {
122c80ce954Sjsg 		reg = pci_conf_read(pc, ca->ca_tag, reg + 4) & 3;
123ad365a85Smickey 		if (reg) {
124ad365a85Smickey 			printf("%s: awakening from state D%d\n",
125ad365a85Smickey 			    sc->sc_dev.dv_xname, reg);
126c80ce954Sjsg 			pci_conf_write(pc, ca->ca_tag, reg + 4, 0);
127ad365a85Smickey 		}
128ad365a85Smickey 	}
129ad365a85Smickey 
130ad365a85Smickey 	(*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
131ad365a85Smickey 	(*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE);
132ad365a85Smickey 	(*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
133ad365a85Smickey 
134ad365a85Smickey 	paa.puc = sc;
135ad365a85Smickey 	paa.intr_string = &puc_cardbus_intr_string;
136ad365a85Smickey 	paa.intr_establish = &puc_cardbus_intr_establish;
13740e7fd94Sderaadt 
138ad365a85Smickey 	puc_common_attach(sc, &paa);
139ad365a85Smickey }
140ad365a85Smickey 
141ad365a85Smickey const char *
puc_cardbus_intr_string(struct puc_attach_args * paa)142ad365a85Smickey puc_cardbus_intr_string(struct puc_attach_args *paa)
143ad365a85Smickey {
144ad365a85Smickey 	struct puc_cardbus_softc *sc = paa->puc;
145ad365a85Smickey 	static char str[16];
146ad365a85Smickey 
147ad365a85Smickey 	snprintf(str, sizeof str, "irq %d", sc->intrline);
148ad365a85Smickey 	return (str);
149ad365a85Smickey }
150ad365a85Smickey 
151ad365a85Smickey void *
puc_cardbus_intr_establish(struct puc_attach_args * paa,int type,int (* func)(void *),void * arg,char * name)152ad365a85Smickey puc_cardbus_intr_establish(struct puc_attach_args *paa, int type,
153ad365a85Smickey     int (*func)(void *), void *arg, char *name)
154ad365a85Smickey {
155ad365a85Smickey 	struct puc_cardbus_softc *sc = paa->puc;
156452fd331Skettenis 	struct puc_softc *psc = &sc->sc_psc;
157ad365a85Smickey 	struct cardbus_devfunc *ct = sc->ct;
158ad365a85Smickey 
159452fd331Skettenis 	psc->sc_ports[paa->port].intrhand =
160452fd331Skettenis 	    cardbus_intr_establish(ct->ct_cc, ct->ct_cf, sc->intrline,
161452fd331Skettenis 		type, func, arg, name);
162452fd331Skettenis 
163452fd331Skettenis 	return (psc->sc_ports[paa->port].intrhand);
164ad365a85Smickey }
165ad365a85Smickey 
166ad365a85Smickey int
puc_cardbus_detach(struct device * self,int flags)167ad365a85Smickey puc_cardbus_detach(struct device *self, int flags)
168ad365a85Smickey {
169452fd331Skettenis 	struct puc_cardbus_softc *sc = (struct puc_cardbus_softc *)self;
170452fd331Skettenis 	struct puc_softc *psc = &sc->sc_psc;
171452fd331Skettenis 	struct cardbus_devfunc *ct = sc->ct;
172ad365a85Smickey 	int i, rv;
173ad365a85Smickey 
174452fd331Skettenis 	for (i = PUC_MAX_PORTS; i--; ) {
175452fd331Skettenis 		if (psc->sc_ports[i].intrhand)
176452fd331Skettenis 			cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf,
177452fd331Skettenis 			    psc->sc_ports[i].intrhand);
178452fd331Skettenis 		if (psc->sc_ports[i].dev)
179452fd331Skettenis 			if ((rv = config_detach(psc->sc_ports[i].dev, flags)))
180ad365a85Smickey 				return (rv);
181452fd331Skettenis 	}
182ad365a85Smickey 
183ad365a85Smickey 	for (i = PUC_NBARS; i--; )
184452fd331Skettenis 		if (psc->sc_bar_mappings[i].mapped)
185452fd331Skettenis 			Cardbus_mapreg_unmap(ct, psc->sc_bar_mappings[i].type,
186452fd331Skettenis 			    psc->sc_bar_mappings[i].t,
187452fd331Skettenis 			    psc->sc_bar_mappings[i].h,
188452fd331Skettenis 			    psc->sc_bar_mappings[i].s);
189ad365a85Smickey 
190ad365a85Smickey 	return (0);
191ad365a85Smickey }
192