i80321.c revision 143728
1135669Scognet/*	$NetBSD: i80321.c,v 1.15 2003/10/06 16:06:05 thorpej Exp $	*/
2135669Scognet
3139735Simp/*-
4135669Scognet * Copyright (c) 2002 Wasabi Systems, Inc.
5135669Scognet * All rights reserved.
6135669Scognet *
7135669Scognet * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8135669Scognet *
9135669Scognet * Redistribution and use in source and binary forms, with or without
10135669Scognet * modification, are permitted provided that the following conditions
11135669Scognet * are met:
12135669Scognet * 1. Redistributions of source code must retain the above copyright
13135669Scognet *    notice, this list of conditions and the following disclaimer.
14135669Scognet * 2. Redistributions in binary form must reproduce the above copyright
15135669Scognet *    notice, this list of conditions and the following disclaimer in the
16135669Scognet *    documentation and/or other materials provided with the distribution.
17135669Scognet * 3. All advertising materials mentioning features or use of this software
18135669Scognet *    must display the following acknowledgement:
19135669Scognet *	This product includes software developed for the NetBSD Project by
20135669Scognet *	Wasabi Systems, Inc.
21135669Scognet * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22135669Scognet *    or promote products derived from this software without specific prior
23135669Scognet *    written permission.
24135669Scognet *
25135669Scognet * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26135669Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27135669Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28135669Scognet * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29135669Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30135669Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31135669Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32135669Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33135669Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34135669Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35135669Scognet * POSSIBILITY OF SUCH DAMAGE.
36135669Scognet */
37135669Scognet
38135669Scognet/*
39135669Scognet * Autoconfiguration support for the Intel i80321 I/O Processor.
40135669Scognet */
41135669Scognet
42135669Scognet#include <sys/cdefs.h>
43135669Scognet__FBSDID("$FreeBSD: head/sys/arm/xscale/i80321/i80321.c 143728 2005-03-17 00:43:57Z cognet $");
44135669Scognet
45135669Scognet#include <sys/param.h>
46135669Scognet#include <sys/systm.h>
47135669Scognet#include <sys/bus.h>
48135669Scognet#include <sys/kernel.h>
49135669Scognet#include <sys/module.h>
50135669Scognet
51135669Scognet#define	_ARM32_BUS_DMA_PRIVATE
52135669Scognet#include <machine/bus.h>
53135669Scognet#include <machine/intr.h>
54135669Scognet
55135669Scognet#include <arm/xscale/i80321/i80321reg.h>
56135669Scognet#include <arm/xscale/i80321/i80321var.h>
57135669Scognet#include <arm/xscale/i80321/i80321_intr.h>
58135669Scognet
59135669Scognet#include <dev/pci/pcireg.h>
60135669Scognet
61135669Scognetvolatile uint32_t intr_enabled;
62135669Scognetuint32_t intr_steer = 0;
63135669Scognet/*
64135669Scognet * Statically-allocated bus_space stucture used to access the
65135669Scognet * i80321's own registers.
66135669Scognet */
67135669Scognetstruct bus_space i80321_bs_tag;
68135669Scognet
69135669Scognet/*
70135669Scognet * There can be only one i80321, so we keep a global pointer to
71135669Scognet * the softc, so board-specific code can use features of the
72135669Scognet * i80321 without having to have a handle on the softc itself.
73135669Scognet */
74135669Scognetstruct i80321_softc *i80321_softc;
75135669Scognet
76135669Scognet/* Built-in devices. */
77135669Scognetstatic const struct iopxs_device {
78135669Scognet	const char *id_name;
79135669Scognet	bus_addr_t id_offset;
80135669Scognet	bus_size_t id_size;
81135669Scognet} iopxs_devices[] = {
82135669Scognet	{ "iopaau",	VERDE_AAU_BASE,		VERDE_AAU_SIZE },
83135669Scognet/*	{ "iopdma",	VERDE_DMA_BASE0,	VERDE_DMA_CHSIZE },	*/
84135669Scognet/*	{ "iopdma",	VERDE_DMA_BASE1,	VERDE_DMA_CHSIZE },	*/
85135669Scognet	{ "iopiic",	VERDE_I2C_BASE0,	VERDE_I2C_CHSIZE },
86135669Scognet	{ "iopiic",	VERDE_I2C_BASE1,	VERDE_I2C_CHSIZE },
87135669Scognet/*	{ "iopssp",	VERDE_SSP_BASE,		VERDE_SSP_SIZE },	*/
88135669Scognet	{ "iopmu",	VERDE_MU_BASE,		VERDE_MU_SIZE },
89135669Scognet	{ "iopwdog",	0,			0 },
90135669Scognet	{ NULL,		0,			0 }
91135669Scognet};
92135669Scognet
93135669Scognet#define PCI_MAPREG_MEM_ADDR(x) ((x) & 0xfffffff0)
94135669Scognet/*
95135669Scognet * i80321_attach:
96135669Scognet *
97135669Scognet *	Board-independent attach routine for the i80321.
98135669Scognet */
99135669Scognetvoid
100135669Scogneti80321_attach(struct i80321_softc *sc)
101135669Scognet{
102135669Scognet
103135669Scognet	i80321_softc = sc;
104135669Scognet	uint32_t preg;
105135669Scognet
106135669Scognet	/* We expect the Memory Controller to be already sliced off. */
107135669Scognet
108135669Scognet	/*
109135669Scognet	 * Program the Inbound windows.
110135669Scognet	 */
111135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR0,
112135669Scognet	    (0xffffffff - (sc->sc_iwin[0].iwin_size - 1)) & 0xffffffc0);
113135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR0,
114135669Scognet	    sc->sc_iwin[0].iwin_xlate);
115135669Scognet	if (sc->sc_is_host) {
116135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
117143728Scognet		    PCIR_BARS, sc->sc_iwin[0].iwin_base_lo);
118135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
119143728Scognet		    PCIR_BARS + 0x04, sc->sc_iwin[0].iwin_base_hi);
120135669Scognet	} else {
121135669Scognet		sc->sc_iwin[0].iwin_base_lo = bus_space_read_4(sc->sc_st,
122143728Scognet		    sc->sc_atu_sh, PCIR_BARS);
123135669Scognet		sc->sc_iwin[0].iwin_base_hi = bus_space_read_4(sc->sc_st,
124143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x04);
125135669Scognet		sc->sc_iwin[0].iwin_base_lo =
126135669Scognet		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[0].iwin_base_lo);
127135669Scognet	}
128135669Scognet
129135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR1,
130135669Scognet	    (0xffffffff - (sc->sc_iwin[1].iwin_size - 1)) & 0xffffffc0);
131135669Scognet
132135669Scognet	/* no xlate for window 1 */
133135669Scognet	if (sc->sc_is_host) {
134135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
135143728Scognet		    PCIR_BARS + 0x08, sc->sc_iwin[1].iwin_base_lo);
136135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
137143728Scognet		    PCIR_BARS + 0x0c, sc->sc_iwin[1].iwin_base_hi);
138135669Scognet	} else {
139135669Scognet		sc->sc_iwin[1].iwin_base_lo = bus_space_read_4(sc->sc_st,
140143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x08);
141135669Scognet		sc->sc_iwin[1].iwin_base_hi = bus_space_read_4(sc->sc_st,
142143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x0c);
143135669Scognet		sc->sc_iwin[1].iwin_base_lo =
144135669Scognet		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo);
145135669Scognet	}
146135669Scognet
147135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR2,
148135669Scognet	    (0xffffffff - (sc->sc_iwin[2].iwin_size - 1)) & 0xffffffc0);
149135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR2,
150135669Scognet	    sc->sc_iwin[2].iwin_xlate);
151135669Scognet
152135669Scognet	if (sc->sc_is_host) {
153135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
154143728Scognet		    PCIR_BARS + 0x10, sc->sc_iwin[2].iwin_base_lo);
155135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
156143728Scognet		    PCIR_BARS + 0x14, sc->sc_iwin[2].iwin_base_hi);
157135669Scognet	} else {
158135669Scognet		sc->sc_iwin[2].iwin_base_lo = bus_space_read_4(sc->sc_st,
159143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x10);
160135669Scognet		sc->sc_iwin[2].iwin_base_hi = bus_space_read_4(sc->sc_st,
161143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x14);
162135669Scognet		sc->sc_iwin[2].iwin_base_lo =
163135669Scognet		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo);
164135669Scognet	}
165135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR3,
166135669Scognet	    (0xffffffff - (sc->sc_iwin[3].iwin_size - 1)) & 0xffffffc0);
167135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR3,
168135669Scognet	    sc->sc_iwin[3].iwin_xlate);
169135669Scognet
170135669Scognet	if (sc->sc_is_host) {
171135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
172135669Scognet		    ATU_IABAR3, sc->sc_iwin[3].iwin_base_lo);
173135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
174135669Scognet		    ATU_IAUBAR3, sc->sc_iwin[3].iwin_base_hi);
175135669Scognet	} else {
176135669Scognet		sc->sc_iwin[3].iwin_base_lo = bus_space_read_4(sc->sc_st,
177135669Scognet		    sc->sc_atu_sh, ATU_IABAR3);
178135669Scognet		sc->sc_iwin[3].iwin_base_hi = bus_space_read_4(sc->sc_st,
179135669Scognet		    sc->sc_atu_sh, ATU_IAUBAR3);
180135669Scognet		sc->sc_iwin[3].iwin_base_lo =
181135669Scognet		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[3].iwin_base_lo);
182135669Scognet	}
183135669Scognet	/*
184135669Scognet	 * Mask (disable) the ATU interrupt sources.
185135669Scognet	 * XXX May want to revisit this if we encounter
186135669Scognet	 * XXX an application that wants it.
187135669Scognet	 */
188135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
189135669Scognet	    ATU_ATUIMR,
190135669Scognet	    ATUIMR_IMW1BU|ATUIMR_ISCEM|ATUIMR_RSCEM|ATUIMR_PST|
191135669Scognet	    ATUIMR_DPE|ATUIMR_P_SERR_ASRT|ATUIMR_PMA|ATUIMR_PTAM|
192135669Scognet	    ATUIMR_PTAT|ATUIMR_PMPE);
193135669Scognet
194135669Scognet	/*
195135669Scognet	 * Program the outbound windows.
196135669Scognet	 */
197135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
198135669Scognet	    ATU_OIOWTVR, sc->sc_ioout_xlate);
199135669Scognet
200135669Scognet	if (!sc->sc_is_host) {
201135669Scognet		sc->sc_owin[0].owin_xlate_lo = sc->sc_iwin[1].iwin_base_lo;
202135669Scognet		sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi;
203135669Scognet	}
204135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
205135669Scognet	    ATU_OMWTVR0, sc->sc_owin[0].owin_xlate_lo);
206135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
207135669Scognet	    ATU_OUMWTVR0, sc->sc_owin[0].owin_xlate_hi);
208135669Scognet
209135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
210135669Scognet	    ATU_OMWTVR1, sc->sc_owin[1].owin_xlate_lo);
211135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
212135669Scognet	    ATU_OUMWTVR1, sc->sc_owin[1].owin_xlate_hi);
213135669Scognet
214135669Scognet	/*
215135669Scognet	 * Set up the ATU configuration register.  All we do
216135669Scognet	 * right now is enable Outbound Windows.
217135669Scognet	 */
218135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUCR,
219135669Scognet	    ATUCR_OUT_EN);
220135669Scognet
221135669Scognet	/*
222135669Scognet	 * Enable bus mastering, memory access, SERR, and parity
223135669Scognet	 * checking on the ATU.
224135669Scognet	 */
225135669Scognet	if (sc->sc_is_host) {
226135669Scognet		preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh,
227135669Scognet		    PCIR_COMMAND);
228135669Scognet		preg |= PCIM_CMD_MEMEN |
229135669Scognet		    PCIM_CMD_BUSMASTEREN | PCIM_CMD_PERRESPEN |
230135669Scognet		    PCIM_CMD_SERRESPEN;
231135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
232135669Scognet		    PCIR_COMMAND, preg);
233135669Scognet		preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh,
234135669Scognet		    PCIR_COMMAND);
235135669Scognet	}
236135669Scognet	/* Initialize the bus space tags. */
237135669Scognet	i80321_io_bs_init(&sc->sc_pci_iot, sc);
238135669Scognet	i80321_mem_bs_init(&sc->sc_pci_memt, sc);
239135669Scognet	intr_enabled = 0;
240135669Scognet	i80321_set_intrmask();
241135669Scognet	i80321_set_intrsteer();
242135669Scognet}
243135669Scognet
244135669Scognet
245135669Scognetstatic __inline uint32_t
246135669Scogneti80321_iintsrc_read(void)
247135669Scognet{
248135669Scognet	uint32_t iintsrc;
249135669Scognet
250135669Scognet	__asm __volatile("mrc p6, 0, %0, c8, c0, 0"
251135669Scognet	    : "=r" (iintsrc));
252135669Scognet
253135669Scognet	/*
254135669Scognet	 * The IINTSRC register shows bits that are active even
255135669Scognet	 * if they are masked in INTCTL, so we have to mask them
256135669Scognet	 * off with the interrupts we consider enabled.
257135669Scognet	 */
258135669Scognet	return (iintsrc & intr_enabled);
259135669Scognet}
260135669Scognet
261135669Scognetint
262135669Scognetarm_get_irqnb(void *clockframe)
263135669Scognet{
264135669Scognet
265135669Scognet	return (i80321_iintsrc_read());
266135669Scognet}
267135669Scognet
268135669Scognet
269