i80321.c revision 139735
1205194Sdelphij/*	$NetBSD: i80321.c,v 1.15 2003/10/06 16:06:05 thorpej Exp $	*/
2205194Sdelphij
3205194Sdelphij/*-
4205194Sdelphij * Copyright (c) 2002 Wasabi Systems, Inc.
5205194Sdelphij * All rights reserved.
6205194Sdelphij *
7205194Sdelphij * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8205194Sdelphij *
9205194Sdelphij * Redistribution and use in source and binary forms, with or without
10205194Sdelphij * modification, are permitted provided that the following conditions
11205194Sdelphij * are met:
12205194Sdelphij * 1. Redistributions of source code must retain the above copyright
13205194Sdelphij *    notice, this list of conditions and the following disclaimer.
14205194Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
15205194Sdelphij *    notice, this list of conditions and the following disclaimer in the
16205194Sdelphij *    documentation and/or other materials provided with the distribution.
17205194Sdelphij * 3. All advertising materials mentioning features or use of this software
18205194Sdelphij *    must display the following acknowledgement:
19205194Sdelphij *	This product includes software developed for the NetBSD Project by
20205194Sdelphij *	Wasabi Systems, Inc.
21205194Sdelphij * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22205194Sdelphij *    or promote products derived from this software without specific prior
23205194Sdelphij *    written permission.
24205194Sdelphij *
25205194Sdelphij * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26205194Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27205194Sdelphij * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28205194Sdelphij * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29205194Sdelphij * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30205194Sdelphij * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31205194Sdelphij * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32205194Sdelphij * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33205194Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34205194Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35205194Sdelphij * POSSIBILITY OF SUCH DAMAGE.
36205194Sdelphij */
37205194Sdelphij
38205194Sdelphij/*
39205194Sdelphij * Autoconfiguration support for the Intel i80321 I/O Processor.
40205194Sdelphij */
41205194Sdelphij
42205194Sdelphij#include <sys/cdefs.h>
43205194Sdelphij__FBSDID("$FreeBSD: head/sys/arm/xscale/i80321/i80321.c 139735 2005-01-05 21:58:49Z imp $");
44205194Sdelphij
45205194Sdelphij#include <sys/param.h>
46205194Sdelphij#include <sys/systm.h>
47205194Sdelphij#include <sys/bus.h>
48205194Sdelphij#include <sys/kernel.h>
49205194Sdelphij#include <sys/module.h>
50205194Sdelphij
51205194Sdelphij#define	_ARM32_BUS_DMA_PRIVATE
52205194Sdelphij#include <machine/bus.h>
53205194Sdelphij#include <machine/intr.h>
54205194Sdelphij
55205194Sdelphij#include <arm/xscale/i80321/i80321reg.h>
56205194Sdelphij#include <arm/xscale/i80321/i80321var.h>
57205194Sdelphij#include <arm/xscale/i80321/i80321_intr.h>
58205194Sdelphij
59205194Sdelphij#include <dev/pci/pcireg.h>
60205194Sdelphij
61205194Sdelphijvolatile uint32_t intr_enabled;
62205194Sdelphijuint32_t intr_steer = 0;
63205194Sdelphij/*
64205194Sdelphij * Statically-allocated bus_space stucture used to access the
65205194Sdelphij * i80321's own registers.
66205194Sdelphij */
67205194Sdelphijstruct bus_space i80321_bs_tag;
68205194Sdelphij
69205194Sdelphij/*
70205194Sdelphij * There can be only one i80321, so we keep a global pointer to
71205194Sdelphij * the softc, so board-specific code can use features of the
72205194Sdelphij * i80321 without having to have a handle on the softc itself.
73205194Sdelphij */
74205194Sdelphijstruct i80321_softc *i80321_softc;
75205194Sdelphij
76205194Sdelphij/* Built-in devices. */
77205194Sdelphijstatic const struct iopxs_device {
78205194Sdelphij	const char *id_name;
79205194Sdelphij	bus_addr_t id_offset;
80205194Sdelphij	bus_size_t id_size;
81205194Sdelphij} iopxs_devices[] = {
82205194Sdelphij	{ "iopaau",	VERDE_AAU_BASE,		VERDE_AAU_SIZE },
83205194Sdelphij/*	{ "iopdma",	VERDE_DMA_BASE0,	VERDE_DMA_CHSIZE },	*/
84205194Sdelphij/*	{ "iopdma",	VERDE_DMA_BASE1,	VERDE_DMA_CHSIZE },	*/
85205194Sdelphij	{ "iopiic",	VERDE_I2C_BASE0,	VERDE_I2C_CHSIZE },
86205194Sdelphij	{ "iopiic",	VERDE_I2C_BASE1,	VERDE_I2C_CHSIZE },
87205194Sdelphij/*	{ "iopssp",	VERDE_SSP_BASE,		VERDE_SSP_SIZE },	*/
88205194Sdelphij	{ "iopmu",	VERDE_MU_BASE,		VERDE_MU_SIZE },
89205194Sdelphij	{ "iopwdog",	0,			0 },
90205194Sdelphij	{ NULL,		0,			0 }
91205194Sdelphij};
92205194Sdelphij
93205194Sdelphij#define PCI_MAPREG_MEM_ADDR(x) ((x) & 0xfffffff0)
94205194Sdelphij/*
95205194Sdelphij * i80321_attach:
96205194Sdelphij *
97205194Sdelphij *	Board-independent attach routine for the i80321.
98205194Sdelphij */
99205194Sdelphijvoid
100205194Sdelphiji80321_attach(struct i80321_softc *sc)
101205194Sdelphij{
102205194Sdelphij
103205194Sdelphij	i80321_softc = sc;
104205194Sdelphij	uint32_t preg;
105205194Sdelphij
106205194Sdelphij	/* We expect the Memory Controller to be already sliced off. */
107205194Sdelphij
108205194Sdelphij	/*
109205194Sdelphij	 * Program the Inbound windows.
110205194Sdelphij	 */
111205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR0,
112205194Sdelphij	    (0xffffffff - (sc->sc_iwin[0].iwin_size - 1)) & 0xffffffc0);
113205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR0,
114205194Sdelphij	    sc->sc_iwin[0].iwin_xlate);
115205194Sdelphij	if (sc->sc_is_host) {
116205194Sdelphij		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
117205194Sdelphij		    PCIR_MAPS, sc->sc_iwin[0].iwin_base_lo);
118205194Sdelphij		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
119205194Sdelphij		    PCIR_MAPS + 0x04, sc->sc_iwin[0].iwin_base_hi);
120205194Sdelphij	} else {
121205194Sdelphij		sc->sc_iwin[0].iwin_base_lo = bus_space_read_4(sc->sc_st,
122205194Sdelphij		    sc->sc_atu_sh, PCIR_MAPS);
123205194Sdelphij		sc->sc_iwin[0].iwin_base_hi = bus_space_read_4(sc->sc_st,
124205194Sdelphij		    sc->sc_atu_sh, PCIR_MAPS + 0x04);
125205194Sdelphij		sc->sc_iwin[0].iwin_base_lo =
126205194Sdelphij		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[0].iwin_base_lo);
127205194Sdelphij	}
128205194Sdelphij
129205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR1,
130205194Sdelphij	    (0xffffffff - (sc->sc_iwin[1].iwin_size - 1)) & 0xffffffc0);
131205194Sdelphij
132205194Sdelphij	/* no xlate for window 1 */
133205194Sdelphij	if (sc->sc_is_host) {
134205194Sdelphij		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
135205194Sdelphij		    PCIR_MAPS + 0x08, sc->sc_iwin[1].iwin_base_lo);
136205194Sdelphij		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
137205194Sdelphij		    PCIR_MAPS + 0x0c, sc->sc_iwin[1].iwin_base_hi);
138205194Sdelphij	} else {
139205194Sdelphij		sc->sc_iwin[1].iwin_base_lo = bus_space_read_4(sc->sc_st,
140205194Sdelphij		    sc->sc_atu_sh, PCIR_MAPS + 0x08);
141205194Sdelphij		sc->sc_iwin[1].iwin_base_hi = bus_space_read_4(sc->sc_st,
142205194Sdelphij		    sc->sc_atu_sh, PCIR_MAPS + 0x0c);
143205194Sdelphij		sc->sc_iwin[1].iwin_base_lo =
144205194Sdelphij		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo);
145205194Sdelphij	}
146205194Sdelphij
147205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR2,
148205194Sdelphij	    (0xffffffff - (sc->sc_iwin[2].iwin_size - 1)) & 0xffffffc0);
149205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR2,
150205194Sdelphij	    sc->sc_iwin[2].iwin_xlate);
151205194Sdelphij
152205194Sdelphij	if (sc->sc_is_host) {
153205194Sdelphij		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
154205194Sdelphij		    PCIR_MAPS + 0x10, sc->sc_iwin[2].iwin_base_lo);
155205194Sdelphij		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
156205194Sdelphij		    PCIR_MAPS + 0x14, sc->sc_iwin[2].iwin_base_hi);
157205194Sdelphij	} else {
158205194Sdelphij		sc->sc_iwin[2].iwin_base_lo = bus_space_read_4(sc->sc_st,
159205194Sdelphij		    sc->sc_atu_sh, PCIR_MAPS + 0x10);
160205194Sdelphij		sc->sc_iwin[2].iwin_base_hi = bus_space_read_4(sc->sc_st,
161205194Sdelphij		    sc->sc_atu_sh, PCIR_MAPS + 0x14);
162205194Sdelphij		sc->sc_iwin[2].iwin_base_lo =
163205194Sdelphij		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo);
164205194Sdelphij	}
165205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR3,
166205194Sdelphij	    (0xffffffff - (sc->sc_iwin[3].iwin_size - 1)) & 0xffffffc0);
167205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR3,
168205194Sdelphij	    sc->sc_iwin[3].iwin_xlate);
169205194Sdelphij
170205194Sdelphij	if (sc->sc_is_host) {
171205194Sdelphij		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
172205194Sdelphij		    ATU_IABAR3, sc->sc_iwin[3].iwin_base_lo);
173205194Sdelphij		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
174205194Sdelphij		    ATU_IAUBAR3, sc->sc_iwin[3].iwin_base_hi);
175205194Sdelphij	} else {
176205194Sdelphij		sc->sc_iwin[3].iwin_base_lo = bus_space_read_4(sc->sc_st,
177205194Sdelphij		    sc->sc_atu_sh, ATU_IABAR3);
178205194Sdelphij		sc->sc_iwin[3].iwin_base_hi = bus_space_read_4(sc->sc_st,
179205194Sdelphij		    sc->sc_atu_sh, ATU_IAUBAR3);
180205194Sdelphij		sc->sc_iwin[3].iwin_base_lo =
181205194Sdelphij		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[3].iwin_base_lo);
182205194Sdelphij	}
183205194Sdelphij	/*
184205194Sdelphij	 * Mask (disable) the ATU interrupt sources.
185205194Sdelphij	 * XXX May want to revisit this if we encounter
186205194Sdelphij	 * XXX an application that wants it.
187205194Sdelphij	 */
188205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
189205194Sdelphij	    ATU_ATUIMR,
190205194Sdelphij	    ATUIMR_IMW1BU|ATUIMR_ISCEM|ATUIMR_RSCEM|ATUIMR_PST|
191205194Sdelphij	    ATUIMR_DPE|ATUIMR_P_SERR_ASRT|ATUIMR_PMA|ATUIMR_PTAM|
192205194Sdelphij	    ATUIMR_PTAT|ATUIMR_PMPE);
193205194Sdelphij
194205194Sdelphij	/*
195205194Sdelphij	 * Program the outbound windows.
196205194Sdelphij	 */
197205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
198205194Sdelphij	    ATU_OIOWTVR, sc->sc_ioout_xlate);
199205194Sdelphij
200205194Sdelphij	if (!sc->sc_is_host) {
201205194Sdelphij		sc->sc_owin[0].owin_xlate_lo = sc->sc_iwin[1].iwin_base_lo;
202205194Sdelphij		sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi;
203205194Sdelphij	}
204205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
205205194Sdelphij	    ATU_OMWTVR0, sc->sc_owin[0].owin_xlate_lo);
206205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
207205194Sdelphij	    ATU_OUMWTVR0, sc->sc_owin[0].owin_xlate_hi);
208205194Sdelphij
209205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
210205194Sdelphij	    ATU_OMWTVR1, sc->sc_owin[1].owin_xlate_lo);
211205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
212205194Sdelphij	    ATU_OUMWTVR1, sc->sc_owin[1].owin_xlate_hi);
213205194Sdelphij
214205194Sdelphij	/*
215205194Sdelphij	 * Set up the ATU configuration register.  All we do
216205194Sdelphij	 * right now is enable Outbound Windows.
217205194Sdelphij	 */
218205194Sdelphij	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUCR,
219205194Sdelphij	    ATUCR_OUT_EN);
220205194Sdelphij
221205194Sdelphij	/*
222205194Sdelphij	 * Enable bus mastering, memory access, SERR, and parity
223205194Sdelphij	 * checking on the ATU.
224205194Sdelphij	 */
225205194Sdelphij	if (sc->sc_is_host) {
226205194Sdelphij		preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh,
227205194Sdelphij		    PCIR_COMMAND);
228205194Sdelphij		preg |= PCIM_CMD_MEMEN |
229205194Sdelphij		    PCIM_CMD_BUSMASTEREN | PCIM_CMD_PERRESPEN |
230205194Sdelphij		    PCIM_CMD_SERRESPEN;
231205194Sdelphij		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
232205194Sdelphij		    PCIR_COMMAND, preg);
233205194Sdelphij		preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh,
234205194Sdelphij		    PCIR_COMMAND);
235205194Sdelphij	}
236205194Sdelphij	/* Initialize the bus space tags. */
237205194Sdelphij	i80321_io_bs_init(&sc->sc_pci_iot, sc);
238205194Sdelphij	i80321_mem_bs_init(&sc->sc_pci_memt, sc);
239205194Sdelphij	intr_enabled = 0;
240205194Sdelphij	i80321_set_intrmask();
241205194Sdelphij	i80321_set_intrsteer();
242205194Sdelphij}
243205194Sdelphij
244205194Sdelphij
245205194Sdelphijstatic __inline uint32_t
246205194Sdelphiji80321_iintsrc_read(void)
247205194Sdelphij{
248205194Sdelphij	uint32_t iintsrc;
249205194Sdelphij
250205194Sdelphij	__asm __volatile("mrc p6, 0, %0, c8, c0, 0"
251205194Sdelphij	    : "=r" (iintsrc));
252205194Sdelphij
253205194Sdelphij	/*
254205194Sdelphij	 * The IINTSRC register shows bits that are active even
255205194Sdelphij	 * if they are masked in INTCTL, so we have to mask them
256205194Sdelphij	 * off with the interrupts we consider enabled.
257205194Sdelphij	 */
258205194Sdelphij	return (iintsrc & intr_enabled);
259205194Sdelphij}
260205194Sdelphij
261205194Sdelphijint
262205194Sdelphijarm_get_irqnb(void *clockframe)
263205194Sdelphij{
264205194Sdelphij
265205194Sdelphij	return (i80321_iintsrc_read());
266205194Sdelphij}
267205194Sdelphij
268205194Sdelphij
269205194Sdelphij