ops-bonito64.c (3548B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 1999, 2000, 2004 MIPS Technologies, Inc. 4 * All rights reserved. 5 * Authors: Carsten Langgaard <carstenl@mips.com> 6 * Maciej W. Rozycki <macro@mips.com> 7 * 8 * MIPS boards specific PCI support. 9 */ 10#include <linux/types.h> 11#include <linux/pci.h> 12#include <linux/kernel.h> 13 14#include <asm/mips-boards/bonito64.h> 15 16#define PCI_ACCESS_READ 0 17#define PCI_ACCESS_WRITE 1 18 19#define CFG_SPACE_REG(offset) (void *)CKSEG1ADDR(_pcictrl_bonito_pcicfg + (offset)) 20#define ID_SEL_BEGIN 10 21#define MAX_DEV_NUM (31 - ID_SEL_BEGIN) 22 23 24static int bonito64_pcibios_config_access(unsigned char access_type, 25 struct pci_bus *bus, 26 unsigned int devfn, int where, 27 u32 * data) 28{ 29 u32 busnum = bus->number; 30 u32 addr, type; 31 u32 dummy; 32 void *addrp; 33 int device = PCI_SLOT(devfn); 34 int function = PCI_FUNC(devfn); 35 int reg = where & ~3; 36 37 if (busnum == 0) { 38 /* Type 0 configuration for onboard PCI bus */ 39 if (device > MAX_DEV_NUM) 40 return -1; 41 42 addr = (1 << (device + ID_SEL_BEGIN)) | (function << 8) | reg; 43 type = 0; 44 } else { 45 /* Type 1 configuration for offboard PCI bus */ 46 addr = (busnum << 16) | (device << 11) | (function << 8) | reg; 47 type = 0x10000; 48 } 49 50 /* Clear aborts */ 51 BONITO_PCICMD |= BONITO_PCICMD_MABORT_CLR | BONITO_PCICMD_MTABORT_CLR; 52 53 BONITO_PCIMAP_CFG = (addr >> 16) | type; 54 55 /* Flush Bonito register block */ 56 dummy = BONITO_PCIMAP_CFG; 57 mmiowb(); 58 59 addrp = CFG_SPACE_REG(addr & 0xffff); 60 if (access_type == PCI_ACCESS_WRITE) { 61 writel(cpu_to_le32(*data), addrp); 62 /* Wait till done */ 63 while (BONITO_PCIMSTAT & 0xF); 64 } else { 65 *data = le32_to_cpu(readl(addrp)); 66 } 67 68 /* Detect Master/Target abort */ 69 if (BONITO_PCICMD & (BONITO_PCICMD_MABORT_CLR | 70 BONITO_PCICMD_MTABORT_CLR)) { 71 /* Error occurred */ 72 73 /* Clear bits */ 74 BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR | 75 BONITO_PCICMD_MTABORT_CLR); 76 77 return -1; 78 } 79 80 return 0; 81 82} 83 84 85/* 86 * We can't address 8 and 16 bit words directly. Instead we have to 87 * read/write a 32bit word and mask/modify the data we actually want. 88 */ 89static int bonito64_pcibios_read(struct pci_bus *bus, unsigned int devfn, 90 int where, int size, u32 * val) 91{ 92 u32 data = 0; 93 94 if ((size == 2) && (where & 1)) 95 return PCIBIOS_BAD_REGISTER_NUMBER; 96 else if ((size == 4) && (where & 3)) 97 return PCIBIOS_BAD_REGISTER_NUMBER; 98 99 if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, 100 &data)) 101 return -1; 102 103 if (size == 1) 104 *val = (data >> ((where & 3) << 3)) & 0xff; 105 else if (size == 2) 106 *val = (data >> ((where & 3) << 3)) & 0xffff; 107 else 108 *val = data; 109 110 return PCIBIOS_SUCCESSFUL; 111} 112 113static int bonito64_pcibios_write(struct pci_bus *bus, unsigned int devfn, 114 int where, int size, u32 val) 115{ 116 u32 data = 0; 117 118 if ((size == 2) && (where & 1)) 119 return PCIBIOS_BAD_REGISTER_NUMBER; 120 else if ((size == 4) && (where & 3)) 121 return PCIBIOS_BAD_REGISTER_NUMBER; 122 123 if (size == 4) 124 data = val; 125 else { 126 if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, 127 where, &data)) 128 return -1; 129 130 if (size == 1) 131 data = (data & ~(0xff << ((where & 3) << 3))) | 132 (val << ((where & 3) << 3)); 133 else if (size == 2) 134 data = (data & ~(0xffff << ((where & 3) << 3))) | 135 (val << ((where & 3) << 3)); 136 } 137 138 if (bonito64_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where, 139 &data)) 140 return -1; 141 142 return PCIBIOS_SUCCESSFUL; 143} 144 145struct pci_ops bonito64_pci_ops = { 146 .read = bonito64_pcibios_read, 147 .write = bonito64_pcibios_write 148};