Path: blob/master/arch/mips/pci/ops-gt64xxx_pci0.c
10820 views
/*1* Copyright (C) 1999, 2000, 2004 MIPS Technologies, Inc.2* All rights reserved.3* Authors: Carsten Langgaard <[email protected]>4* Maciej W. Rozycki <[email protected]>5*6* This program is free software; you can distribute it and/or modify it7* under the terms of the GNU General Public License (Version 2) as8* published by the Free Software Foundation.9*10* This program is distributed in the hope it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* for more details.14*15* You should have received a copy of the GNU General Public License along16* with this program; if not, write to the Free Software Foundation, Inc.,17* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.18*/19#include <linux/types.h>20#include <linux/pci.h>21#include <linux/kernel.h>2223#include <asm/gt64120.h>2425#define PCI_ACCESS_READ 026#define PCI_ACCESS_WRITE 12728/*29* PCI configuration cycle AD bus definition30*/31/* Type 0 */32#define PCI_CFG_TYPE0_REG_SHF 033#define PCI_CFG_TYPE0_FUNC_SHF 83435/* Type 1 */36#define PCI_CFG_TYPE1_REG_SHF 037#define PCI_CFG_TYPE1_FUNC_SHF 838#define PCI_CFG_TYPE1_DEV_SHF 1139#define PCI_CFG_TYPE1_BUS_SHF 164041static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type,42struct pci_bus *bus, unsigned int devfn, int where, u32 * data)43{44unsigned char busnum = bus->number;45u32 intr;4647if ((busnum == 0) && (devfn >= PCI_DEVFN(31, 0)))48return -1; /* Because of a bug in the galileo (for slot 31). */4950/* Clear cause register bits */51GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |52GT_INTRCAUSE_TARABORT0_BIT));5354/* Setup address */55GT_WRITE(GT_PCI0_CFGADDR_OFS,56(busnum << GT_PCI0_CFGADDR_BUSNUM_SHF) |57(devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |58((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |59GT_PCI0_CFGADDR_CONFIGEN_BIT);6061if (access_type == PCI_ACCESS_WRITE) {62if (busnum == 0 && PCI_SLOT(devfn) == 0) {63/*64* The Galileo system controller is acting65* differently than other devices.66*/67GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);68} else69__GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);70} else {71if (busnum == 0 && PCI_SLOT(devfn) == 0) {72/*73* The Galileo system controller is acting74* differently than other devices.75*/76*data = GT_READ(GT_PCI0_CFGDATA_OFS);77} else78*data = __GT_READ(GT_PCI0_CFGDATA_OFS);79}8081/* Check for master or target abort */82intr = GT_READ(GT_INTRCAUSE_OFS);8384if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {85/* Error occurred */8687/* Clear bits */88GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |89GT_INTRCAUSE_TARABORT0_BIT));9091return -1;92}9394return 0;95}969798/*99* We can't address 8 and 16 bit words directly. Instead we have to100* read/write a 32bit word and mask/modify the data we actually want.101*/102static int gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn,103int where, int size, u32 * val)104{105u32 data = 0;106107if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,108where, &data))109return PCIBIOS_DEVICE_NOT_FOUND;110111if (size == 1)112*val = (data >> ((where & 3) << 3)) & 0xff;113else if (size == 2)114*val = (data >> ((where & 3) << 3)) & 0xffff;115else116*val = data;117118return PCIBIOS_SUCCESSFUL;119}120121static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn,122int where, int size, u32 val)123{124u32 data = 0;125126if (size == 4)127data = val;128else {129if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus,130devfn, where, &data))131return PCIBIOS_DEVICE_NOT_FOUND;132133if (size == 1)134data = (data & ~(0xff << ((where & 3) << 3))) |135(val << ((where & 3) << 3));136else if (size == 2)137data = (data & ~(0xffff << ((where & 3) << 3))) |138(val << ((where & 3) << 3));139}140141if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn,142where, &data))143return PCIBIOS_DEVICE_NOT_FOUND;144145return PCIBIOS_SUCCESSFUL;146}147148struct pci_ops gt64xxx_pci0_ops = {149.read = gt64xxx_pci0_pcibios_read,150.write = gt64xxx_pci0_pcibios_write151};152153154