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