puc_cardbus.c revision 1.6
1/*	$OpenBSD: puc_cardbus.c,v 1.6 2010/03/27 21:40:13 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#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
35struct puc_cardbus_softc {
36	struct puc_softc sc_psc;
37
38	struct cardbus_devfunc *ct;
39	int intrline;
40};
41
42int	puc_cardbus_match(struct device *, void *, void *);
43void	puc_cardbus_attach(struct device *, struct device *, void *);
44int	puc_cardbus_detach(struct device *, int);
45
46const char *puc_cardbus_intr_string(struct puc_attach_args *);
47void *puc_cardbus_intr_establish(struct puc_attach_args *, int,
48    int (*)(void *), void *, char *);
49
50struct cfattach puc_cardbus_ca = {
51	sizeof(struct puc_cardbus_softc), puc_cardbus_match,
52	puc_cardbus_attach, puc_cardbus_detach
53};
54
55int
56puc_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
79void
80puc_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 (!cardbus_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.hwtype = COM_UART_OX16C950;		/* XXX */
140	paa.intr_string = &puc_cardbus_intr_string;
141	paa.intr_establish = &puc_cardbus_intr_establish;
142	puc_common_attach(sc, &paa);
143}
144
145const char *
146puc_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
155void *
156puc_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
170int
171puc_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