ahc_pci.c revision 76634
1250079Scarl/*
2250079Scarl * FreeBSD, PCI product support functions
3289542Scem *
4250079Scarl * Copyright (c) 1995-2001 Justin T. Gibbs
5250079Scarl * All rights reserved.
6250079Scarl *
7250079Scarl * Redistribution and use in source and binary forms, with or without
8250079Scarl * modification, are permitted provided that the following conditions
9250079Scarl * are met:
10250079Scarl * 1. Redistributions of source code must retain the above copyright
11250079Scarl *    notice, this list of conditions, and the following disclaimer,
12250079Scarl *    without modification, immediately at the beginning of the file.
13250079Scarl * 2. The name of the author may not be used to endorse or promote products
14250079Scarl *    derived from this software without specific prior written permission.
15250079Scarl *
16250079Scarl * Alternatively, this software may be distributed under the terms of the
17250079Scarl * GNU Public License ("GPL").
18250079Scarl *
19250079Scarl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20250079Scarl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21250079Scarl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22250079Scarl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23250079Scarl * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24250079Scarl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25250079Scarl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26250079Scarl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27250079Scarl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28250079Scarl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29250079Scarl * SUCH DAMAGE.
30250079Scarl *
31250079Scarl * $Id$
32250079Scarl *
33250079Scarl * $FreeBSD: head/sys/dev/aic7xxx/ahc_pci.c 76634 2001-05-15 19:41:12Z gibbs $
34250079Scarl */
35250079Scarl
36250079Scarl#include <dev/aic7xxx/aic7xxx_freebsd.h>
37250079Scarl
38250079Scarl#define	AHC_PCI_IOADDR  PCIR_MAPS	/* I/O Address */
39289207Scem#define	AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */
40250079Scarl
41250079Scarlstatic int ahc_pci_probe(device_t dev);
42250079Scarlstatic int ahc_pci_attach(device_t dev);
43250079Scarl
44250079Scarlstatic device_method_t ahc_pci_methods[] = {
45250079Scarl	/* Device interface */
46250079Scarl	DEVMETHOD(device_probe,		ahc_pci_probe),
47250079Scarl	DEVMETHOD(device_attach,	ahc_pci_attach),
48250079Scarl	DEVMETHOD(device_detach,	ahc_detach),
49250079Scarl	{ 0, 0 }
50250079Scarl};
51250079Scarl
52250079Scarlstatic driver_t ahc_pci_driver = {
53250079Scarl	"ahc",
54250079Scarl	ahc_pci_methods,
55250079Scarl	sizeof(struct ahc_softc)
56250079Scarl};
57250079Scarl
58250079Scarlstatic devclass_t ahc_devclass;
59250079Scarl
60250079ScarlDRIVER_MODULE(ahc, pci, ahc_pci_driver, ahc_devclass, 0, 0);
61250079ScarlDRIVER_MODULE(ahc, cardbus, ahc_pci_driver, ahc_devclass, 0, 0);
62250079ScarlMODULE_DEPEND(ahc_pci, ahc, 1, 1, 1);
63289648ScemMODULE_VERSION(ahc_pci, 1);
64250079Scarl
65289539Scemstatic int
66289648Scemahc_pci_probe(device_t dev)
67250079Scarl{
68250079Scarl	struct	ahc_pci_identity *entry;
69250079Scarl
70250079Scarl	entry = ahc_find_pci_device(dev);
71250079Scarl	if (entry != NULL) {
72289648Scem		device_set_desc(dev, entry->name);
73250079Scarl		return (0);
74250079Scarl	}
75289610Scem	return (ENXIO);
76289610Scem}
77289610Scem
78289610Scemstatic int
79289610Scemahc_pci_attach(device_t dev)
80289610Scem{
81289610Scem	struct	 ahc_pci_identity *entry;
82289610Scem	struct	 ahc_softc *ahc;
83289610Scem	char	*name;
84289610Scem	int	 error;
85289610Scem
86289610Scem	entry = ahc_find_pci_device(dev);
87289539Scem	if (entry == NULL)
88289539Scem		return (ENXIO);
89289539Scem
90289539Scem	/*
91289539Scem	 * Allocate a softc for this card and
92289539Scem	 * set it up for attachment by our
93289539Scem	 * common detect routine.
94289539Scem	 */
95255274Scarl	name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT);
96255274Scarl	if (name == NULL)
97255274Scarl		return (ENOMEM);
98255274Scarl	strcpy(name, device_get_nameunit(dev));
99250079Scarl	ahc = ahc_alloc(dev, name);
100250079Scarl	if (ahc == NULL)
101255274Scarl		return (ENOMEM);
102250079Scarl
103289397Scem	ahc_set_unit(ahc, device_get_unit(dev));
104250079Scarl
105250079Scarl	/* Allocate a dmatag for our SCB DMA maps */
106250079Scarl	/* XXX Should be a child of the PCI bus dma tag */
107250079Scarl	error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
108250079Scarl				   /*boundary*/0,
109250079Scarl				   /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
110250079Scarl				   /*highaddr*/BUS_SPACE_MAXADDR,
111250079Scarl				   /*filter*/NULL, /*filterarg*/NULL,
112250079Scarl				   /*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG,
113250079Scarl				   /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
114289543Scem				   /*flags*/BUS_DMA_ALLOCNOW,
115289543Scem				   &ahc->parent_dmat);
116289543Scem
117289543Scem	if (error != 0) {
118289543Scem		printf("ahc_pci_attach: Could not allocate DMA tag "
119250079Scarl		       "- error %d\n", error);
120250079Scarl		ahc_free(ahc);
121250079Scarl		return (ENOMEM);
122250079Scarl	}
123250079Scarl	ahc->dev_softc = dev;
124250079Scarl	error = ahc_pci_config(ahc, entry);
125250079Scarl	if (error != 0) {
126250079Scarl		ahc_free(ahc);
127289546Scem		return (error);
128250079Scarl	}
129289546Scem
130250079Scarl	ahc_attach(ahc);
131250079Scarl	return (0);
132289542Scem}
133289542Scem
134289542Scemint
135289542Scemahc_pci_map_registers(struct ahc_softc *ahc)
136289542Scem{
137289542Scem	struct	resource *regs;
138289542Scem	u_int	command;
139289542Scem	int	regs_type;
140289542Scem	int	regs_id;
141289542Scem
142289542Scem	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
143289542Scem	regs = NULL;
144289542Scem	regs_type = 0;
145289542Scem	regs_id = 0;
146289546Scem#ifdef AHC_ALLOW_MEMIO
147289546Scem	if ((command & PCIM_CMD_MEMEN) != 0) {
148289546Scem
149289546Scem		regs_type = SYS_RES_MEMORY;
150289546Scem		regs_id = AHC_PCI_MEMADDR;
151289546Scem		regs = bus_alloc_resource(ahc->dev_softc, regs_type,
152289546Scem					  &regs_id, 0, ~0, 1, RF_ACTIVE);
153289546Scem		if (regs != NULL) {
154289546Scem			ahc->tag = rman_get_bustag(regs);
155289546Scem			ahc->bsh = rman_get_bushandle(regs);
156289546Scem
157289546Scem			/*
158289542Scem			 * Do a quick test to see if memory mapped
159289542Scem			 * I/O is functioning correctly.
160289542Scem			 */
161289542Scem			if (ahc_inb(ahc, HCNTRL) == 0xFF) {
162289542Scem				device_printf(ahc->dev_softc,
163289542Scem				       "PCI Device %d:%d:%d failed memory "
164289542Scem				       "mapped test.  Using PIO.\n",
165289542Scem				       ahc_get_pci_bus(ahc->dev_softc),
166289542Scem				       ahc_get_pci_slot(ahc->dev_softc),
167289542Scem				       ahc_get_pci_function(ahc->dev_softc));
168250079Scarl				bus_release_resource(ahc->dev_softc, regs_type,
169250079Scarl						     regs_id, regs);
170250079Scarl				regs = NULL;
171255274Scarl			} else {
172250079Scarl				command &= ~PCIM_CMD_PORTEN;
173250079Scarl				ahc_pci_write_config(ahc->dev_softc,
174250079Scarl						     PCIR_COMMAND,
175250079Scarl						     command, /*bytes*/1);
176250079Scarl			}
177250079Scarl		}
178250079Scarl	}
179250079Scarl#endif
180289546Scem	if (regs == NULL && (command & PCIM_CMD_PORTEN) != 0) {
181289546Scem		regs_type = SYS_RES_IOPORT;
182289546Scem		regs_id = AHC_PCI_IOADDR;
183289546Scem		regs = bus_alloc_resource(ahc->dev_softc, regs_type,
184289546Scem					  &regs_id, 0, ~0, 1, RF_ACTIVE);
185289546Scem		ahc->tag = rman_get_bustag(regs);
186289546Scem		ahc->bsh = rman_get_bushandle(regs);
187250079Scarl		command &= ~PCIM_CMD_MEMEN;
188289610Scem		ahc_pci_write_config(ahc->dev_softc,
189289610Scem				     PCIR_COMMAND,
190289610Scem				     command, /*bytes*/1);
191289539Scem	}
192289542Scem	ahc->platform_data->regs_res_type = regs_type;
193289542Scem	ahc->platform_data->regs_res_id = regs_id;
194289542Scem	ahc->platform_data->regs = regs;
195289543Scem
196289542Scem	if (regs == NULL) {
197289542Scem		device_printf(ahc->dev_softc,
198289539Scem			      "can't allocate register resources\n");
199289539Scem		return (ENOMEM);
200289539Scem	}
201289539Scem	return (0);
202289539Scem}
203289542Scem
204289546Scemint
205289546Scemahc_pci_map_int(struct ahc_softc *ahc)
206289546Scem{
207289546Scem	int zero;
208289542Scem
209289542Scem	zero = 0;
210289546Scem	ahc->platform_data->irq =
211289546Scem	    bus_alloc_resource(ahc->dev_softc, SYS_RES_IRQ, &zero,
212289542Scem			       0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
213289542Scem	if (ahc->platform_data->irq == NULL)
214289542Scem		return (ENOMEM);
215289546Scem	ahc->platform_data->irq_res_type = SYS_RES_IRQ;
216289542Scem	return (0);
217289542Scem}
218289542Scem
219289542Scemvoid
220289542Scemahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state)
221289542Scem{
222289542Scem	uint32_t cap;
223250079Scarl	u_int cap_offset;
224250079Scarl
225289234Scem	/*
226289234Scem	 * Traverse the capability list looking for
227289234Scem	 * the power management capability.
228289234Scem	 */
229289234Scem	cap = 0;
230289234Scem	cap_offset = ahc_pci_read_config(ahc->dev_softc,
231289234Scem					 PCIR_CAP_PTR, /*bytes*/1);
232289234Scem	while (cap_offset != 0) {
233289234Scem
234289234Scem		cap = ahc_pci_read_config(ahc->dev_softc,
235289234Scem					  cap_offset, /*bytes*/4);
236289234Scem		if ((cap & 0xFF) == 1
237289234Scem		 && ((cap >> 16) & 0x3) > 0) {
238289234Scem			uint32_t pm_control;
239289234Scem
240289234Scem			pm_control = ahc_pci_read_config(ahc->dev_softc,
241289234Scem							 cap_offset + 4,
242289234Scem							 /*bytes*/4);
243289234Scem			pm_control &= ~0x3;
244289234Scem			pm_control |= new_state;
245255279Scarl			ahc_pci_write_config(ahc->dev_softc,
246255279Scarl					     cap_offset + 4,
247255279Scarl					     pm_control, /*bytes*/2);
248255279Scarl			break;
249255279Scarl		}
250255279Scarl		cap_offset = (cap >> 8) & 0xFF;
251255279Scarl	}
252250079Scarl}
253255279Scarl