1/*-
2 * Copyright (c) 2003 Hidetoshi Shimokawa
3 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the acknowledgement as bellow:
16 *
17 *    This product includes software developed by K. Kobayashi and H. SHimokawa
18 *
19 * 4. The name of the author may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 * $FreeBSD: src/sys/dev/firewire/fwohci_pci.c,v 1.60 2007/06/06 14:31:36 simokawa Exp $
35 */
36
37#include <OS.h>
38#include <KernelExport.h>
39#include <lock.h>
40#include <SupportDefs.h>
41#include <PCI.h>
42
43#include <stdlib.h>
44#include <stdio.h>
45#include <string.h>
46#include <malloc.h>
47
48#include "util.h"
49#include "fwdebug.h"
50#include "fwglue.h"
51#include "queue.h"
52#include "firewire.h"
53#include "iec13213.h"
54#include "firewirereg.h"
55
56#include "fwdma.h"
57#include "fwohcireg.h"
58#include "fwohcivar.h"
59
60#define PCIM_CMD_IOS		0x0001
61#define	PCIM_CMD_MEMEN		0x0002
62#define	PCIM_CMD_BUSMASTEREN	0x0004
63#define	PCIM_CMD_MWRICEN	0x0010
64#define	PCIM_CMD_PERRESPEN	0x0040
65#define	PCIM_CMD_SERRESPEN	0x0100
66
67extern pci_module_info	*gPci;
68extern pci_info *pciInfo[MAX_CARDS];
69extern fwohci_softc_t *gFwohci_softc[MAX_CARDS];
70extern struct firewire_softc *gFirewire_softc[MAX_CARDS];
71
72status_t
73fwohci_pci_detach(int index)
74{
75	fwohci_softc_t *sc = gFwohci_softc[index];
76	int s;
77
78	s = splfw();
79
80	fwohci_stop(sc);
81
82//	bus_generic_detach(self);
83	firewire_detach(gFirewire_softc[index]);
84/*	if (sc->fc.bdev) {
85		device_delete_child(self, sc->fc.bdev);
86		sc->fc.bdev = NULL;
87	}*/
88
89	/* disable interrupts that might have been switched on */
90	OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_EN);
91	remove_io_interrupt_handler (sc->irq, fwohci_intr, sc);
92	delete_area(sc->regArea);
93
94	fwohci_detach(sc);
95	mtx_destroy(FW_GMTX(&sc->fc));
96	splx(s);
97	return B_OK;
98}
99
100static void
101fwohci_pci_add_child(int index)
102{
103	struct fwohci_softc *sc;
104	int err = 0;
105
106	sc = gFwohci_softc[index];
107
108/*	child = device_add_child(dev, name, unit);
109	if (child == NULL)
110		return (child);
111
112	sc->fc.bdev = child;
113	device_set_ivars(child, (void *)&sc->fc);*/
114
115//	err = device_probe_and_attach(child);
116	err = firewire_attach(&sc->fc, gFirewire_softc[index]);
117
118	if (err) {
119		device_printf(dev, "firewire_attach failed with err=%d\n",
120		    err);
121		fwohci_pci_detach(index);
122//		device_delete_child(dev, child);
123		return;
124	}
125	/* XXX
126	 * Clear the bus reset event flag to start transactions even when
127	 * interrupt is disabled during the boot process.
128	 */
129//	if (cold) {
130//		int s;
131//		DELAY(250); /* 2 cycles */
132//		s = splfw();
133//		fwohci_poll((void *)sc, 0, -1);
134//		splx(s);
135//	}
136
137}
138
139status_t
140fwohci_pci_attach(int index)
141{
142	fwohci_softc_t *sc = gFwohci_softc[index];
143	pci_info *info = pciInfo[index];
144	uint32 olatency, latency, ocache_line, cache_line;
145	uint32 val;
146
147	mtx_init(FW_GMTX(&sc->fc), "firewire", NULL, MTX_DEF);
148
149	val = gPci->read_pci_config(info->bus, info->device, info->function,
150			PCI_command, 2);
151	val |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN;
152
153#if 1  /* for broken hardware */
154	val &= ~PCIM_CMD_MWRICEN;
155	val &= ~(PCIM_CMD_SERRESPEN | PCIM_CMD_PERRESPEN);
156#endif
157	gPci->write_pci_config(info->bus, info->device, info->function,
158			PCI_command, 2, val);
159
160	/*
161	 * Some Sun PCIO-2 FireWire controllers have their intpin register
162	 * bogusly set to 0, although it should be 3. Correct that.
163	 */
164	if (info->vendor_id == FW_VENDORID_SUN && info->device_id == (FW_DEVICE_PCIO2FW >> 16) &&
165			info->u.h0.interrupt_pin == 0)
166		info->u.h0.interrupt_pin = 3;
167
168	latency = olatency = gPci->read_pci_config(info->bus, info->device, info->function,
169			PCI_latency, 1);
170#define DEF_LATENCY 0x20
171	if (olatency < DEF_LATENCY) {
172		latency = DEF_LATENCY;
173		gPci->write_pci_config(info->bus, info->device, info->function,
174				PCI_latency, 1, latency);
175	}
176
177	cache_line = ocache_line = gPci->read_pci_config(info->bus, info->device,
178			info->function, PCI_line_size, 1);
179#define DEF_CACHE_LINE 8
180	if (ocache_line < DEF_CACHE_LINE) {
181		cache_line = DEF_CACHE_LINE;
182		gPci->write_pci_config(info->bus, info->device, info->function,
183				PCI_line_size, 1, cache_line);
184	}
185	TRACE("latency timer %lx -> %lx.\n", olatency, latency);
186	TRACE("cache size %lx -> %lx.\n", ocache_line, cache_line);
187
188	// get IRQ
189	sc->irq = gPci->read_pci_config(info->bus, info->device, info->function,
190			PCI_interrupt_line, 1);
191	if (sc->irq == 0 || sc->irq == 0xff) {
192		ERROR("no IRQ assigned\n");
193		goto err;
194	}
195	TRACE("IRQ %d\n", sc->irq);
196
197	// map registers into memory
198//	val = gPci->read_pci_config(info->bus, info->device, info->function, 0x14, 4);
199//	val &= PCI_address_memory_32_mask;
200//	TRACE("hardware register address %p\n", (void *) val);
201	TRACE("hardware register address %lx\n", info->u.h0.base_registers[0]);
202	sc->regArea = map_mem(&sc->regAddr, (void *)info->u.h0.base_registers[0], 0x800,
203			B_READ_AREA | B_WRITE_AREA, "fw ohci register");
204	if (sc->regArea < B_OK) {
205		ERROR("can't map hardware registers\n");
206		goto err;
207	}
208	TRACE("mapped registers to %p\n", sc->regAddr);
209
210	// setup interrupt handler
211	if (install_io_interrupt_handler(sc->irq, fwohci_intr,
212				sc, 0) < B_OK) {
213		ERROR("can't install interrupt handler\n");
214		goto err;
215	}
216
217	if (fwohci_init(sc) < B_OK){
218
219		ERROR("fwohci_init failed");
220		goto err;
221	}
222	fwohci_pci_add_child(index);
223	return B_OK;
224err:
225	delete_area(sc->regArea);
226	mtx_destroy(FW_GMTX(&sc->fc));
227	return B_ERROR;
228}
229