Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 1999, 2000, 2004  MIPS Technologies, Inc.
0004  *  All rights reserved.
0005  *  Authors: Carsten Langgaard <carstenl@mips.com>
0006  *       Maciej W. Rozycki <macro@mips.com>
0007  *
0008  * MIPS boards specific PCI support.
0009  */
0010 #include <linux/types.h>
0011 #include <linux/pci.h>
0012 #include <linux/kernel.h>
0013 
0014 #include <asm/mips-boards/bonito64.h>
0015 
0016 #define PCI_ACCESS_READ  0
0017 #define PCI_ACCESS_WRITE 1
0018 
0019 #define CFG_SPACE_REG(offset) (void *)CKSEG1ADDR(_pcictrl_bonito_pcicfg + (offset))
0020 #define ID_SEL_BEGIN 10
0021 #define MAX_DEV_NUM (31 - ID_SEL_BEGIN)
0022 
0023 
0024 static int bonito64_pcibios_config_access(unsigned char access_type,
0025                       struct pci_bus *bus,
0026                       unsigned int devfn, int where,
0027                       u32 * data)
0028 {
0029     u32 busnum = bus->number;
0030     u32 addr, type;
0031     u32 dummy;
0032     void *addrp;
0033     int device = PCI_SLOT(devfn);
0034     int function = PCI_FUNC(devfn);
0035     int reg = where & ~3;
0036 
0037     if (busnum == 0) {
0038         /* Type 0 configuration for onboard PCI bus */
0039         if (device > MAX_DEV_NUM)
0040             return -1;
0041 
0042         addr = (1 << (device + ID_SEL_BEGIN)) | (function << 8) | reg;
0043         type = 0;
0044     } else {
0045         /* Type 1 configuration for offboard PCI bus */
0046         addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
0047         type = 0x10000;
0048     }
0049 
0050     /* Clear aborts */
0051     BONITO_PCICMD |= BONITO_PCICMD_MABORT_CLR | BONITO_PCICMD_MTABORT_CLR;
0052 
0053     BONITO_PCIMAP_CFG = (addr >> 16) | type;
0054 
0055     /* Flush Bonito register block */
0056     dummy = BONITO_PCIMAP_CFG;
0057     mmiowb();
0058 
0059     addrp = CFG_SPACE_REG(addr & 0xffff);
0060     if (access_type == PCI_ACCESS_WRITE) {
0061         writel(cpu_to_le32(*data), addrp);
0062         /* Wait till done */
0063         while (BONITO_PCIMSTAT & 0xF);
0064     } else {
0065         *data = le32_to_cpu(readl(addrp));
0066     }
0067 
0068     /* Detect Master/Target abort */
0069     if (BONITO_PCICMD & (BONITO_PCICMD_MABORT_CLR |
0070                  BONITO_PCICMD_MTABORT_CLR)) {
0071         /* Error occurred */
0072 
0073         /* Clear bits */
0074         BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR |
0075                   BONITO_PCICMD_MTABORT_CLR);
0076 
0077         return -1;
0078     }
0079 
0080     return 0;
0081 
0082 }
0083 
0084 
0085 /*
0086  * We can't address 8 and 16 bit words directly.  Instead we have to
0087  * read/write a 32bit word and mask/modify the data we actually want.
0088  */
0089 static int bonito64_pcibios_read(struct pci_bus *bus, unsigned int devfn,
0090                  int where, int size, u32 * val)
0091 {
0092     u32 data = 0;
0093 
0094     if ((size == 2) && (where & 1))
0095         return PCIBIOS_BAD_REGISTER_NUMBER;
0096     else if ((size == 4) && (where & 3))
0097         return PCIBIOS_BAD_REGISTER_NUMBER;
0098 
0099     if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
0100                        &data))
0101         return -1;
0102 
0103     if (size == 1)
0104         *val = (data >> ((where & 3) << 3)) & 0xff;
0105     else if (size == 2)
0106         *val = (data >> ((where & 3) << 3)) & 0xffff;
0107     else
0108         *val = data;
0109 
0110     return PCIBIOS_SUCCESSFUL;
0111 }
0112 
0113 static int bonito64_pcibios_write(struct pci_bus *bus, unsigned int devfn,
0114                   int where, int size, u32 val)
0115 {
0116     u32 data = 0;
0117 
0118     if ((size == 2) && (where & 1))
0119         return PCIBIOS_BAD_REGISTER_NUMBER;
0120     else if ((size == 4) && (where & 3))
0121         return PCIBIOS_BAD_REGISTER_NUMBER;
0122 
0123     if (size == 4)
0124         data = val;
0125     else {
0126         if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
0127                            where, &data))
0128             return -1;
0129 
0130         if (size == 1)
0131             data = (data & ~(0xff << ((where & 3) << 3))) |
0132                 (val << ((where & 3) << 3));
0133         else if (size == 2)
0134             data = (data & ~(0xffff << ((where & 3) << 3))) |
0135                 (val << ((where & 3) << 3));
0136     }
0137 
0138     if (bonito64_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
0139                        &data))
0140         return -1;
0141 
0142     return PCIBIOS_SUCCESSFUL;
0143 }
0144 
0145 struct pci_ops bonito64_pci_ops = {
0146     .read = bonito64_pcibios_read,
0147     .write = bonito64_pcibios_write
0148 };