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$");
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#define PCI_MAPREG_MEM_ADDR(x) ((x) & 0xfffffff0)
77135669Scognet/*
78135669Scognet * i80321_attach:
79135669Scognet *
80135669Scognet *	Board-independent attach routine for the i80321.
81135669Scognet */
82135669Scognetvoid
83135669Scogneti80321_attach(struct i80321_softc *sc)
84135669Scognet{
85135669Scognet
86135669Scognet	i80321_softc = sc;
87135669Scognet	uint32_t preg;
88135669Scognet
89135669Scognet	/* We expect the Memory Controller to be already sliced off. */
90135669Scognet
91135669Scognet	/*
92135669Scognet	 * Program the Inbound windows.
93135669Scognet	 */
94135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR0,
95135669Scognet	    (0xffffffff - (sc->sc_iwin[0].iwin_size - 1)) & 0xffffffc0);
96135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR0,
97135669Scognet	    sc->sc_iwin[0].iwin_xlate);
98135669Scognet	if (sc->sc_is_host) {
99135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
100143728Scognet		    PCIR_BARS, sc->sc_iwin[0].iwin_base_lo);
101135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
102143728Scognet		    PCIR_BARS + 0x04, sc->sc_iwin[0].iwin_base_hi);
103135669Scognet	} else {
104135669Scognet		sc->sc_iwin[0].iwin_base_lo = bus_space_read_4(sc->sc_st,
105143728Scognet		    sc->sc_atu_sh, PCIR_BARS);
106135669Scognet		sc->sc_iwin[0].iwin_base_hi = bus_space_read_4(sc->sc_st,
107143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x04);
108135669Scognet		sc->sc_iwin[0].iwin_base_lo =
109135669Scognet		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[0].iwin_base_lo);
110135669Scognet	}
111135669Scognet
112135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR1,
113135669Scognet	    (0xffffffff - (sc->sc_iwin[1].iwin_size - 1)) & 0xffffffc0);
114135669Scognet
115135669Scognet	/* no xlate for window 1 */
116135669Scognet	if (sc->sc_is_host) {
117135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
118143728Scognet		    PCIR_BARS + 0x08, sc->sc_iwin[1].iwin_base_lo);
119135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
120143728Scognet		    PCIR_BARS + 0x0c, sc->sc_iwin[1].iwin_base_hi);
121135669Scognet	} else {
122135669Scognet		sc->sc_iwin[1].iwin_base_lo = bus_space_read_4(sc->sc_st,
123143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x08);
124135669Scognet		sc->sc_iwin[1].iwin_base_hi = bus_space_read_4(sc->sc_st,
125143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x0c);
126135669Scognet		sc->sc_iwin[1].iwin_base_lo =
127135669Scognet		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo);
128135669Scognet	}
129135669Scognet
130135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR2,
131135669Scognet	    (0xffffffff - (sc->sc_iwin[2].iwin_size - 1)) & 0xffffffc0);
132135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR2,
133135669Scognet	    sc->sc_iwin[2].iwin_xlate);
134135669Scognet
135135669Scognet	if (sc->sc_is_host) {
136135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
137143728Scognet		    PCIR_BARS + 0x10, sc->sc_iwin[2].iwin_base_lo);
138135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
139143728Scognet		    PCIR_BARS + 0x14, sc->sc_iwin[2].iwin_base_hi);
140135669Scognet	} else {
141135669Scognet		sc->sc_iwin[2].iwin_base_lo = bus_space_read_4(sc->sc_st,
142143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x10);
143135669Scognet		sc->sc_iwin[2].iwin_base_hi = bus_space_read_4(sc->sc_st,
144143728Scognet		    sc->sc_atu_sh, PCIR_BARS + 0x14);
145135669Scognet		sc->sc_iwin[2].iwin_base_lo =
146135669Scognet		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo);
147135669Scognet	}
148135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IALR3,
149135669Scognet	    (0xffffffff - (sc->sc_iwin[3].iwin_size - 1)) & 0xffffffc0);
150135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_IATVR3,
151135669Scognet	    sc->sc_iwin[3].iwin_xlate);
152135669Scognet
153135669Scognet	if (sc->sc_is_host) {
154135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
155135669Scognet		    ATU_IABAR3, sc->sc_iwin[3].iwin_base_lo);
156135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
157135669Scognet		    ATU_IAUBAR3, sc->sc_iwin[3].iwin_base_hi);
158135669Scognet	} else {
159135669Scognet		sc->sc_iwin[3].iwin_base_lo = bus_space_read_4(sc->sc_st,
160135669Scognet		    sc->sc_atu_sh, ATU_IABAR3);
161135669Scognet		sc->sc_iwin[3].iwin_base_hi = bus_space_read_4(sc->sc_st,
162135669Scognet		    sc->sc_atu_sh, ATU_IAUBAR3);
163135669Scognet		sc->sc_iwin[3].iwin_base_lo =
164135669Scognet		    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[3].iwin_base_lo);
165135669Scognet	}
166135669Scognet	/*
167135669Scognet	 * Mask (disable) the ATU interrupt sources.
168135669Scognet	 * XXX May want to revisit this if we encounter
169135669Scognet	 * XXX an application that wants it.
170135669Scognet	 */
171135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
172135669Scognet	    ATU_ATUIMR,
173135669Scognet	    ATUIMR_IMW1BU|ATUIMR_ISCEM|ATUIMR_RSCEM|ATUIMR_PST|
174135669Scognet	    ATUIMR_DPE|ATUIMR_P_SERR_ASRT|ATUIMR_PMA|ATUIMR_PTAM|
175135669Scognet	    ATUIMR_PTAT|ATUIMR_PMPE);
176135669Scognet
177135669Scognet	/*
178135669Scognet	 * Program the outbound windows.
179135669Scognet	 */
180135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
181135669Scognet	    ATU_OIOWTVR, sc->sc_ioout_xlate);
182135669Scognet
183135669Scognet	if (!sc->sc_is_host) {
184135669Scognet		sc->sc_owin[0].owin_xlate_lo = sc->sc_iwin[1].iwin_base_lo;
185135669Scognet		sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi;
186135669Scognet	}
187135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
188135669Scognet	    ATU_OMWTVR0, sc->sc_owin[0].owin_xlate_lo);
189135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
190135669Scognet	    ATU_OUMWTVR0, sc->sc_owin[0].owin_xlate_hi);
191135669Scognet
192135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
193135669Scognet	    ATU_OMWTVR1, sc->sc_owin[1].owin_xlate_lo);
194135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
195135669Scognet	    ATU_OUMWTVR1, sc->sc_owin[1].owin_xlate_hi);
196135669Scognet
197135669Scognet	/*
198135669Scognet	 * Set up the ATU configuration register.  All we do
199135669Scognet	 * right now is enable Outbound Windows.
200135669Scognet	 */
201135669Scognet	bus_space_write_4(sc->sc_st, sc->sc_atu_sh, ATU_ATUCR,
202135669Scognet	    ATUCR_OUT_EN);
203135669Scognet
204135669Scognet	/*
205135669Scognet	 * Enable bus mastering, memory access, SERR, and parity
206135669Scognet	 * checking on the ATU.
207135669Scognet	 */
208135669Scognet	if (sc->sc_is_host) {
209135669Scognet		preg = bus_space_read_4(sc->sc_st, sc->sc_atu_sh,
210135669Scognet		    PCIR_COMMAND);
211135669Scognet		preg |= PCIM_CMD_MEMEN |
212135669Scognet		    PCIM_CMD_BUSMASTEREN | PCIM_CMD_PERRESPEN |
213135669Scognet		    PCIM_CMD_SERRESPEN;
214135669Scognet		bus_space_write_4(sc->sc_st, sc->sc_atu_sh,
215135669Scognet		    PCIR_COMMAND, preg);
216135669Scognet	}
217135669Scognet	/* Initialize the bus space tags. */
218135669Scognet	i80321_io_bs_init(&sc->sc_pci_iot, sc);
219135669Scognet	i80321_mem_bs_init(&sc->sc_pci_memt, sc);
220135669Scognet	intr_enabled = 0;
221135669Scognet	i80321_set_intrmask();
222135669Scognet	i80321_set_intrsteer();
223135669Scognet}
224135669Scognet
225135669Scognet
226135669Scognetstatic __inline uint32_t
227135669Scogneti80321_iintsrc_read(void)
228135669Scognet{
229135669Scognet	uint32_t iintsrc;
230135669Scognet
231135669Scognet	__asm __volatile("mrc p6, 0, %0, c8, c0, 0"
232135669Scognet	    : "=r" (iintsrc));
233135669Scognet
234135669Scognet	/*
235135669Scognet	 * The IINTSRC register shows bits that are active even
236135669Scognet	 * if they are masked in INTCTL, so we have to mask them
237135669Scognet	 * off with the interrupts we consider enabled.
238135669Scognet	 */
239135669Scognet	return (iintsrc & intr_enabled);
240135669Scognet}
241135669Scognet
242135669Scognetint
243193847Smarcelarm_get_next_irq(int last __unused)
244135669Scognet{
245147166Scognet	int irq;
246135669Scognet
247147166Scognet	if ((irq = i80321_iintsrc_read()))
248147166Scognet		return (ffs(irq) - 1);
249147166Scognet	return (-1);
250135669Scognet}
251