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, ®,
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