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