1/* 2 * ops-vr41xx.c, PCI configuration routines for the PCIU of NEC VR4100 series. 3 * 4 * Copyright (C) 2001-2003 MontaVista Software Inc. 5 * Author: Yoichi Yuasa <source@mvista.com> 6 * Copyright (C) 2004-2005 Yoichi Yuasa <yuasa@linux-mips.org> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22/* 23 * Changes: 24 * MontaVista Software Inc. <source@mvista.com> 25 * - New creation, NEC VR4122 and VR4131 are supported. 26 */ 27#include <linux/pci.h> 28#include <linux/types.h> 29 30#include <asm/io.h> 31 32#define PCICONFDREG (void __iomem *)KSEG1ADDR(0x0f000c14) 33#define PCICONFAREG (void __iomem *)KSEG1ADDR(0x0f000c18) 34 35static inline int set_pci_configuration_address(unsigned char number, 36 unsigned int devfn, int where) 37{ 38 if (number == 0) { 39 /* 40 * Type 0 configuration 41 */ 42 if (PCI_SLOT(devfn) < 11 || where > 0xff) 43 return -EINVAL; 44 45 writel((1U << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) | 46 (where & 0xfc), PCICONFAREG); 47 } else { 48 /* 49 * Type 1 configuration 50 */ 51 if (where > 0xff) 52 return -EINVAL; 53 54 writel(((uint32_t)number << 16) | ((devfn & 0xff) << 8) | 55 (where & 0xfc) | 1U, PCICONFAREG); 56 } 57 58 return 0; 59} 60 61static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, 62 int size, uint32_t *val) 63{ 64 uint32_t data; 65 66 *val = 0xffffffffU; 67 if (set_pci_configuration_address(bus->number, devfn, where) < 0) 68 return PCIBIOS_DEVICE_NOT_FOUND; 69 70 data = readl(PCICONFDREG); 71 72 switch (size) { 73 case 1: 74 *val = (data >> ((where & 3) << 3)) & 0xffU; 75 break; 76 case 2: 77 *val = (data >> ((where & 2) << 3)) & 0xffffU; 78 break; 79 case 4: 80 *val = data; 81 break; 82 default: 83 return PCIBIOS_FUNC_NOT_SUPPORTED; 84 } 85 86 return PCIBIOS_SUCCESSFUL; 87} 88 89static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, 90 int size, uint32_t val) 91{ 92 uint32_t data; 93 int shift; 94 95 if (set_pci_configuration_address(bus->number, devfn, where) < 0) 96 return PCIBIOS_DEVICE_NOT_FOUND; 97 98 data = readl(PCICONFDREG); 99 100 switch (size) { 101 case 1: 102 shift = (where & 3) << 3; 103 data &= ~(0xffU << shift); 104 data |= ((val & 0xffU) << shift); 105 break; 106 case 2: 107 shift = (where & 2) << 3; 108 data &= ~(0xffffU << shift); 109 data |= ((val & 0xffffU) << shift); 110 break; 111 case 4: 112 data = val; 113 break; 114 default: 115 return PCIBIOS_FUNC_NOT_SUPPORTED; 116 } 117 118 writel(data, PCICONFDREG); 119 120 return PCIBIOS_SUCCESSFUL; 121} 122 123struct pci_ops vr41xx_pci_ops = { 124 .read = pci_config_read, 125 .write = pci_config_write, 126}; 127