puc_cardbus.c revision 1.1
1/*	$OpenBSD: puc_cardbus.c,v 1.1 2006/07/31 11:06:27 mickey 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	struct cardbus_devfunc *ct = ca->ca_ct;
60	cardbus_chipset_tag_t cc = ct->ct_cc;
61	cardbus_function_tag_t cf = ct->ct_cf;
62	cardbusreg_t bhlc, reg;
63
64	bhlc = cardbus_conf_read(cc, cf, ca->ca_tag, CARDBUS_BHLC_REG);
65	if (PCI_HDRTYPE_TYPE(bhlc) != 0)
66		return(0);
67
68	/* this one is some sort of a bridge and not a puc */
69	if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_OXFORD2 &&
70	    PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_OXFORD2_EXSYS_EX41098)
71		return (0);
72
73	reg = cardbus_conf_read(cc, cf, ca->ca_tag, PCI_SUBSYS_ID_REG);
74	if (puc_find_description(PCI_VENDOR(ca->ca_id),
75	    PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg)))
76		return (10);
77
78	return (0);
79}
80
81void
82puc_cardbus_attach(struct device *parent, struct device *self, void *aux)
83{
84	struct puc_cardbus_softc *csc = (struct puc_cardbus_softc *)self;
85	struct puc_softc *sc = &csc->sc_psc;
86	struct cardbus_attach_args *ca = aux;
87	struct cardbus_devfunc *ct = ca->ca_ct;
88	cardbus_chipset_tag_t cc = ct->ct_cc;
89	cardbus_function_tag_t cf = ct->ct_cf;
90	struct puc_attach_args paa;
91	cardbusreg_t reg;
92	int i;
93
94	Cardbus_function_enable(ct);
95
96	csc->ct = ct;
97
98	reg = cardbus_conf_read(cc, cf, ca->ca_tag, PCI_SUBSYS_ID_REG);
99	sc->sc_desc = puc_find_description(PCI_VENDOR(ca->ca_id),
100	    PCI_PRODUCT(ca->ca_id), PCI_VENDOR(reg), PCI_PRODUCT(reg));
101
102	puc_print_ports(sc->sc_desc);
103
104	/* the fifth one is some memory we dunno */
105	for (i = 0; i < PUC_NBARS; i++) {
106		cardbusreg_t type;
107		int bar;
108
109		sc->sc_bar_mappings[i].mapped = 0;
110		bar = PCI_MAPREG_START + 4 * i;
111		if (!cardbus_mapreg_probe(cc, cf, ca->ca_tag, bar, &type))
112			continue;
113
114		if (!(sc->sc_bar_mappings[i].mapped = !Cardbus_mapreg_map(ct,
115		    bar, type, 0,
116		    &sc->sc_bar_mappings[i].t, &sc->sc_bar_mappings[i].h,
117		    &sc->sc_bar_mappings[i].a, &sc->sc_bar_mappings[i].s)))
118			printf("%s: couldn't map BAR at offset 0x%lx\n",
119			    sc->sc_dev.dv_xname, (long)bar);
120		sc->sc_bar_mappings[i].type = type;
121	}
122
123	csc->intrline = ca->ca_intrline;
124
125	if (cardbus_get_capability(cc, cf, ca->ca_tag, PCI_CAP_PWRMGMT, &reg,
126	    0)) {
127		reg = cardbus_conf_read(cc, cf, ca->ca_tag, reg + 4) & 3;
128		if (reg) {
129			printf("%s: awakening from state D%d\n",
130			    sc->sc_dev.dv_xname, reg);
131			cardbus_conf_write(cc, cf, ca->ca_tag, reg + 4, 0);
132		}
133	}
134
135	(*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
136	(*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE);
137	(*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
138
139	paa.puc = sc;
140	paa.hwtype = COM_UART_OX16C950;		/* XXX */
141	paa.intr_string = &puc_cardbus_intr_string;
142	paa.intr_establish = &puc_cardbus_intr_establish;
143	puc_common_attach(sc, &paa);
144}
145
146const char *
147puc_cardbus_intr_string(struct puc_attach_args *paa)
148{
149	struct puc_cardbus_softc *sc = paa->puc;
150	static char str[16];
151
152	snprintf(str, sizeof str, "irq %d", sc->intrline);
153	return (str);
154}
155
156void *
157puc_cardbus_intr_establish(struct puc_attach_args *paa, int type,
158    int (*func)(void *), void *arg, char *name)
159{
160	struct puc_cardbus_softc *sc = paa->puc;
161	struct cardbus_devfunc *ct = sc->ct;
162
163	return (cardbus_intr_establish(ct->ct_cc, ct->ct_cf, sc->intrline,
164	    type, func, arg));
165}
166
167int
168puc_cardbus_detach(struct device *self, int flags)
169{
170	struct puc_cardbus_softc *csc = (struct puc_cardbus_softc *)self;
171	struct puc_softc *sc = &csc->sc_psc;
172	struct cardbus_devfunc *ct = csc->ct;
173	int i, rv;
174
175	for (i = PUC_MAX_PORTS; i--; )
176		if (sc->sc_ports[i].dev)
177			if ((rv = config_detach(sc->sc_ports[i].dev, flags)))
178				return (rv);
179
180	for (i = PUC_NBARS; i--; )
181		if (sc->sc_bar_mappings[i].mapped)
182			Cardbus_mapreg_unmap(ct, sc->sc_bar_mappings[i].type,
183			    sc->sc_bar_mappings[i].t, sc->sc_bar_mappings[i].h,
184			    sc->sc_bar_mappings[i].s);
185
186	return (0);
187}
188