11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2aa0980b8090878bf42bc73a13d051a203a201d7dMaciej W. Rozycki * Copyright (C) 1999, 2000, 2004 MIPS Technologies, Inc. 3aa0980b8090878bf42bc73a13d051a203a201d7dMaciej W. Rozycki * All rights reserved. 4aa0980b8090878bf42bc73a13d051a203a201d7dMaciej W. Rozycki * Authors: Carsten Langgaard <carstenl@mips.com> 5aa0980b8090878bf42bc73a13d051a203a201d7dMaciej W. Rozycki * Maciej W. Rozycki <macro@mips.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can distribute it and/or modify it 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License (Version 2) as 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope it will be useful, but WITHOUT 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for more details. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc., 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MIPS boards specific PCI support. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mips-boards/bonito64.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCI_ACCESS_READ 0 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCI_ACCESS_WRITE 1 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3242d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian#define CFG_SPACE_REG(offset) (void *)CKSEG1ADDR(_pcictrl_bonito_pcicfg + (offset)) 3342d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian#define ID_SEL_BEGIN 10 3442d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian#define MAX_DEV_NUM (31 - ID_SEL_BEGIN) 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bonito64_pcibios_config_access(unsigned char access_type, 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_bus *bus, 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int devfn, int where, 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 * data) 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4242d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian u32 busnum = bus->number; 4342d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian u32 addr, type; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dummy; 4542d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian void *addrp; 4642d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian int device = PCI_SLOT(devfn); 4742d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian int function = PCI_FUNC(devfn); 4842d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian int reg = where & ~3; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (busnum == 0) { 5142d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian /* Type 0 configuration for onboard PCI bus */ 5242d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian if (device > MAX_DEV_NUM) 5342d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian return -1; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5542d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian addr = (1 << (device + ID_SEL_BEGIN)) | (function << 8) | reg; 5642d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian type = 0; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5842d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian /* Type 1 configuration for offboard PCI bus */ 5942d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian addr = (busnum << 16) | (device << 11) | (function << 8) | reg; 6042d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian type = 0x10000; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6342d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian /* Clear aborts */ 6442d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian BONITO_PCICMD |= BONITO_PCICMD_MABORT_CLR | BONITO_PCICMD_MTABORT_CLR; 6542d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian 6642d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian BONITO_PCIMAP_CFG = (addr >> 16) | type; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Flush Bonito register block */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dummy = BONITO_PCIMAP_CFG; 7042d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian mmiowb(); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7242d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian addrp = CFG_SPACE_REG(addr & 0xffff); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (access_type == PCI_ACCESS_WRITE) { 7442d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian writel(cpu_to_le32(*data), addrp); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait till done */ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (BONITO_PCIMSTAT & 0xF); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7842d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian *data = le32_to_cpu(readl(addrp)); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Detect Master/Target abort */ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (BONITO_PCICMD & (BONITO_PCICMD_MABORT_CLR | 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BONITO_PCICMD_MTABORT_CLR)) { 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Error occurred */ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear bits */ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR | 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BONITO_PCICMD_MTABORT_CLR); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9442d226c7248a28ff8c478c06b7e9bd9ef5d73574Songmao Tian 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can't address 8 and 16 bit words directly. Instead we have to 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read/write a 32bit word and mask/modify the data we actually want. 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bonito64_pcibios_read(struct pci_bus *bus, unsigned int devfn, 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int where, int size, u32 * val) 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 data = 0; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((size == 2) && (where & 1)) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PCIBIOS_BAD_REGISTER_NUMBER; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if ((size == 4) && (where & 3)) 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PCIBIOS_BAD_REGISTER_NUMBER; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &data)) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size == 1) 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *val = (data >> ((where & 3) << 3)) & 0xff; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (size == 2) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *val = (data >> ((where & 3) << 3)) & 0xffff; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *val = data; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PCIBIOS_SUCCESSFUL; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bonito64_pcibios_write(struct pci_bus *bus, unsigned int devfn, 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int where, int size, u32 val) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 data = 0; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((size == 2) && (where & 1)) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PCIBIOS_BAD_REGISTER_NUMBER; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if ((size == 4) && (where & 3)) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PCIBIOS_BAD_REGISTER_NUMBER; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size == 4) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = val; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds where, &data)) 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size == 1) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = (data & ~(0xff << ((where & 3) << 3))) | 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (val << ((where & 3) << 3)); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (size == 2) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = (data & ~(0xffff << ((where & 3) << 3))) | 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (val << ((where & 3) << 3)); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bonito64_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where, 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &data)) 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PCIBIOS_SUCCESSFUL; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pci_ops bonito64_pci_ops = { 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = bonito64_pcibios_read, 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = bonito64_pcibios_write 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 162