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  * Copyright (C) 2009 Lemote Inc.
0009  * Author: Wu Zhangjin <wuzhangjin@gmail.com>
0010  */
0011 #include <linux/types.h>
0012 #include <linux/pci.h>
0013 #include <linux/kernel.h>
0014 #include <linux/export.h>
0015 
0016 #include <loongson.h>
0017 
0018 #ifdef CONFIG_CS5536
0019 #include <cs5536/cs5536_pci.h>
0020 #include <cs5536/cs5536.h>
0021 #endif
0022 
0023 #define PCI_ACCESS_READ  0
0024 #define PCI_ACCESS_WRITE 1
0025 
0026 #define CFG_SPACE_REG(offset) \
0027     (void *)CKSEG1ADDR(LOONGSON_PCICFG_BASE | (offset))
0028 #define ID_SEL_BEGIN 11
0029 #define MAX_DEV_NUM (31 - ID_SEL_BEGIN)
0030 
0031 
0032 static int loongson_pcibios_config_access(unsigned char access_type,
0033                       struct pci_bus *bus,
0034                       unsigned int devfn, int where,
0035                       u32 *data)
0036 {
0037     u32 busnum = bus->number;
0038     u32 addr, type;
0039     u32 dummy;
0040     void *addrp;
0041     int device = PCI_SLOT(devfn);
0042     int function = PCI_FUNC(devfn);
0043     int reg = where & ~3;
0044 
0045     if (busnum == 0) {
0046         /* board-specific part,currently,only fuloong2f,yeeloong2f
0047          * use CS5536, fuloong2e use via686b, gdium has no
0048          * south bridge
0049          */
0050 #ifdef CONFIG_CS5536
0051         /* cs5536_pci_conf_read4/write4() will call _rdmsr/_wrmsr() to
0052          * access the regsters PCI_MSR_ADDR, PCI_MSR_DATA_LO,
0053          * PCI_MSR_DATA_HI, which is bigger than PCI_MSR_CTRL, so, it
0054          * will not go this branch, but the others. so, no calling dead
0055          * loop here.
0056          */
0057         if ((PCI_IDSEL_CS5536 == device) && (reg < PCI_MSR_CTRL)) {
0058             switch (access_type) {
0059             case PCI_ACCESS_READ:
0060                 *data = cs5536_pci_conf_read4(function, reg);
0061                 break;
0062             case PCI_ACCESS_WRITE:
0063                 cs5536_pci_conf_write4(function, reg, *data);
0064                 break;
0065             }
0066             return 0;
0067         }
0068 #endif
0069         /* Type 0 configuration for onboard PCI bus */
0070         if (device > MAX_DEV_NUM)
0071             return -1;
0072 
0073         addr = (1 << (device + ID_SEL_BEGIN)) | (function << 8) | reg;
0074         type = 0;
0075     } else {
0076         /* Type 1 configuration for offboard PCI bus */
0077         addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
0078         type = 0x10000;
0079     }
0080 
0081     /* Clear aborts */
0082     LOONGSON_PCICMD |= LOONGSON_PCICMD_MABORT_CLR | \
0083                 LOONGSON_PCICMD_MTABORT_CLR;
0084 
0085     LOONGSON_PCIMAP_CFG = (addr >> 16) | type;
0086 
0087     /* Flush Bonito register block */
0088     dummy = LOONGSON_PCIMAP_CFG;
0089     mmiowb();
0090 
0091     addrp = CFG_SPACE_REG(addr & 0xffff);
0092     if (access_type == PCI_ACCESS_WRITE)
0093         writel(cpu_to_le32(*data), addrp);
0094     else
0095         *data = le32_to_cpu(readl(addrp));
0096 
0097     /* Detect Master/Target abort */
0098     if (LOONGSON_PCICMD & (LOONGSON_PCICMD_MABORT_CLR |
0099                  LOONGSON_PCICMD_MTABORT_CLR)) {
0100         /* Error occurred */
0101 
0102         /* Clear bits */
0103         LOONGSON_PCICMD |= (LOONGSON_PCICMD_MABORT_CLR |
0104                   LOONGSON_PCICMD_MTABORT_CLR);
0105 
0106         return -1;
0107     }
0108 
0109     return 0;
0110 
0111 }
0112 
0113 
0114 /*
0115  * We can't address 8 and 16 bit words directly.  Instead we have to
0116  * read/write a 32bit word and mask/modify the data we actually want.
0117  */
0118 static int loongson_pcibios_read(struct pci_bus *bus, unsigned int devfn,
0119                  int where, int size, u32 *val)
0120 {
0121     u32 data = 0;
0122 
0123     if ((size == 2) && (where & 1))
0124         return PCIBIOS_BAD_REGISTER_NUMBER;
0125     else if ((size == 4) && (where & 3))
0126         return PCIBIOS_BAD_REGISTER_NUMBER;
0127 
0128     if (loongson_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
0129                        &data))
0130         return -1;
0131 
0132     if (size == 1)
0133         *val = (data >> ((where & 3) << 3)) & 0xff;
0134     else if (size == 2)
0135         *val = (data >> ((where & 3) << 3)) & 0xffff;
0136     else
0137         *val = data;
0138 
0139     return PCIBIOS_SUCCESSFUL;
0140 }
0141 
0142 static int loongson_pcibios_write(struct pci_bus *bus, unsigned int devfn,
0143                   int where, int size, u32 val)
0144 {
0145     u32 data = 0;
0146 
0147     if ((size == 2) && (where & 1))
0148         return PCIBIOS_BAD_REGISTER_NUMBER;
0149     else if ((size == 4) && (where & 3))
0150         return PCIBIOS_BAD_REGISTER_NUMBER;
0151 
0152     if (size == 4)
0153         data = val;
0154     else {
0155         if (loongson_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
0156                     where, &data))
0157             return -1;
0158 
0159         if (size == 1)
0160             data = (data & ~(0xff << ((where & 3) << 3))) |
0161                 (val << ((where & 3) << 3));
0162         else if (size == 2)
0163             data = (data & ~(0xffff << ((where & 3) << 3))) |
0164                 (val << ((where & 3) << 3));
0165     }
0166 
0167     if (loongson_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
0168                        &data))
0169         return -1;
0170 
0171     return PCIBIOS_SUCCESSFUL;
0172 }
0173 
0174 struct pci_ops loongson_pci_ops = {
0175     .read = loongson_pcibios_read,
0176     .write = loongson_pcibios_write
0177 };
0178 
0179 #ifdef CONFIG_CS5536
0180 DEFINE_RAW_SPINLOCK(msr_lock);
0181 
0182 void _rdmsr(u32 msr, u32 *hi, u32 *lo)
0183 {
0184     struct pci_bus bus = {
0185         .number = PCI_BUS_CS5536
0186     };
0187     u32 devfn = PCI_DEVFN(PCI_IDSEL_CS5536, 0);
0188     unsigned long flags;
0189 
0190     raw_spin_lock_irqsave(&msr_lock, flags);
0191     loongson_pcibios_write(&bus, devfn, PCI_MSR_ADDR, 4, msr);
0192     loongson_pcibios_read(&bus, devfn, PCI_MSR_DATA_LO, 4, lo);
0193     loongson_pcibios_read(&bus, devfn, PCI_MSR_DATA_HI, 4, hi);
0194     raw_spin_unlock_irqrestore(&msr_lock, flags);
0195 }
0196 EXPORT_SYMBOL(_rdmsr);
0197 
0198 void _wrmsr(u32 msr, u32 hi, u32 lo)
0199 {
0200     struct pci_bus bus = {
0201         .number = PCI_BUS_CS5536
0202     };
0203     u32 devfn = PCI_DEVFN(PCI_IDSEL_CS5536, 0);
0204     unsigned long flags;
0205 
0206     raw_spin_lock_irqsave(&msr_lock, flags);
0207     loongson_pcibios_write(&bus, devfn, PCI_MSR_ADDR, 4, msr);
0208     loongson_pcibios_write(&bus, devfn, PCI_MSR_DATA_LO, 4, lo);
0209     loongson_pcibios_write(&bus, devfn, PCI_MSR_DATA_HI, 4, hi);
0210     raw_spin_unlock_irqrestore(&msr_lock, flags);
0211 }
0212 EXPORT_SYMBOL(_wrmsr);
0213 #endif