1/*	$OpenBSD: sili_pci.c,v 1.16 2024/05/24 06:02:58 jsg Exp $ */
2
3/*
4 * Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/param.h>
20#include <sys/systm.h>
21#include <sys/device.h>
22#include <sys/timeout.h>
23
24#include <machine/bus.h>
25
26#include <dev/pci/pcireg.h>
27#include <dev/pci/pcivar.h>
28#include <dev/pci/pcidevs.h>
29
30#include <dev/ata/atascsi.h>
31
32#include <dev/ic/silireg.h>
33#include <dev/ic/silivar.h>
34
35int	sili_pci_match(struct device *, void *, void *);
36void	sili_pci_attach(struct device *, struct device *, void *);
37int	sili_pci_detach(struct device *, int);
38int	sili_pci_activate(struct device *, int);
39
40struct sili_pci_softc {
41	struct sili_softc	psc_sili;
42
43	pci_chipset_tag_t	psc_pc;
44	pcitag_t		psc_tag;
45
46	void			*psc_ih;
47};
48
49const struct cfattach sili_pci_ca = {
50	sizeof(struct sili_pci_softc),
51	sili_pci_match,
52	sili_pci_attach,
53	sili_pci_detach,
54	sili_pci_activate
55};
56
57struct sili_device {
58	pci_vendor_id_t		sd_vendor;
59	pci_product_id_t	sd_product;
60	u_int			sd_nports;
61};
62
63const struct sili_device *sili_lookup(struct pci_attach_args *);
64
65static const struct sili_device sili_devices[] = {
66	{ PCI_VENDOR_CMDTECH,	PCI_PRODUCT_CMDTECH_3124, 4 },
67	{ PCI_VENDOR_CMDTECH,	PCI_PRODUCT_CMDTECH_3131, 1 },
68	{ PCI_VENDOR_CMDTECH,	PCI_PRODUCT_CMDTECH_3132, 2 },
69	{ PCI_VENDOR_CMDTECH,	PCI_PRODUCT_CMDTECH_3531, 1 },
70	{ PCI_VENDOR_CMDTECH,	PCI_PRODUCT_CMDTECH_AAR_1220SA, 2 },
71	{ PCI_VENDOR_CMDTECH,	PCI_PRODUCT_CMDTECH_AAR_1225SA, 2 },
72	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_3124, 4 }
73};
74
75const struct sili_device *
76sili_lookup(struct pci_attach_args *pa)
77{
78	int				i;
79	const struct sili_device	*sd;
80
81	for (i = 0; i < nitems(sili_devices); i++) {
82		sd = &sili_devices[i];
83		if (sd->sd_vendor == PCI_VENDOR(pa->pa_id) &&
84		    sd->sd_product == PCI_PRODUCT(pa->pa_id))
85			return (sd);
86	}
87
88	return (NULL);
89}
90
91int
92sili_pci_match(struct device *parent, void *match, void *aux)
93{
94	return (sili_lookup((struct pci_attach_args *)aux) != NULL);
95}
96
97void
98sili_pci_attach(struct device *parent, struct device *self, void *aux)
99{
100	struct sili_pci_softc		*psc = (void *)self;
101	struct sili_softc		*sc = &psc->psc_sili;
102	struct pci_attach_args		*pa = aux;
103	const struct sili_device	*sd;
104	pcireg_t			memtype;
105	pci_intr_handle_t		ih;
106	const char			*intrstr;
107
108	sd = sili_lookup(pa);
109
110	psc->psc_pc = pa->pa_pc;
111	psc->psc_tag = pa->pa_tag;
112	psc->psc_ih = NULL;
113	sc->sc_dmat = pa->pa_dmat;
114	sc->sc_ios_global = 0;
115	sc->sc_ios_port = 0;
116	sc->sc_nports = sd->sd_nports;
117
118	memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag,
119	    SILI_PCI_BAR_GLOBAL);
120	if (pci_mapreg_map(pa, SILI_PCI_BAR_GLOBAL, memtype, 0,
121	    &sc->sc_iot_global, &sc->sc_ioh_global,
122	    NULL, &sc->sc_ios_global, 0) != 0) {
123		printf(": unable to map global registers\n");
124		return;
125	}
126
127	memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag,
128	    SILI_PCI_BAR_PORT);
129	if (pci_mapreg_map(pa, SILI_PCI_BAR_PORT, memtype, 0,
130	    &sc->sc_iot_port, &sc->sc_ioh_port,
131	    NULL, &sc->sc_ios_port, 0) != 0) {
132		printf(": unable to map port registers\n");
133		goto unmap_global;
134	}
135
136	/* hook up the interrupt */
137	if (pci_intr_map(pa, &ih)) {
138		printf(": unable to map interrupt\n");
139		goto unmap_port;
140	}
141	intrstr = pci_intr_string(psc->psc_pc, ih);
142	psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_BIO,
143	    sili_intr, sc, sc->sc_dev.dv_xname);
144	if (psc->psc_ih == NULL) {
145		printf(": unable to map interrupt%s%s\n",
146		    intrstr == NULL ? "" : " at ",
147		    intrstr == NULL ? "" : intrstr);
148		goto unmap_port;
149	}
150	printf(": %s", intrstr);
151
152	if (sili_attach(sc) != 0) {
153		/* error printed by sili_attach */
154		goto deintr;
155	}
156
157	return;
158
159deintr:
160	pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
161	psc->psc_ih = NULL;
162unmap_port:
163	bus_space_unmap(sc->sc_iot_port, sc->sc_ioh_port, sc->sc_ios_port);
164	sc->sc_ios_port = 0;
165unmap_global:
166	bus_space_unmap(sc->sc_iot_global, sc->sc_ioh_global,
167	    sc->sc_ios_global);
168	sc->sc_ios_global = 0;
169}
170
171int
172sili_pci_detach(struct device *self, int flags)
173{
174	struct sili_pci_softc		*psc = (struct sili_pci_softc *)self;
175	struct sili_softc		*sc = &psc->psc_sili;
176	int				rv;
177
178	rv = sili_detach(sc, flags);
179	if (rv != 0)
180		return (rv);
181
182	if (psc->psc_ih != NULL) {
183		pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
184		psc->psc_ih = NULL;
185	}
186	if (sc->sc_ios_port != 0) {
187		bus_space_unmap(sc->sc_iot_port, sc->sc_ioh_port,
188		    sc->sc_ios_port);
189		sc->sc_ios_port = 0;
190	}
191	if (sc->sc_ios_global != 0) {
192		bus_space_unmap(sc->sc_iot_global, sc->sc_ioh_global,
193		    sc->sc_ios_global);
194		sc->sc_ios_global = 0;
195	}
196
197	return (0);
198}
199
200int
201sili_pci_activate(struct device *self, int act)
202{
203	struct sili_softc		*sc = (struct sili_softc *)self;
204	int				 rv = 0;
205
206	switch (act) {
207	case DVACT_RESUME:
208		sili_resume(sc);
209		rv = config_activate_children(self, act);
210		break;
211	default:
212		rv = config_activate_children(self, act);
213		break;
214	}
215	return (rv);
216}
217