0001
0002
0003
0004
0005
0006
0007
0008
0009
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
0047
0048
0049
0050 #ifdef CONFIG_CS5536
0051
0052
0053
0054
0055
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
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
0077 addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
0078 type = 0x10000;
0079 }
0080
0081
0082 LOONGSON_PCICMD |= LOONGSON_PCICMD_MABORT_CLR | \
0083 LOONGSON_PCICMD_MTABORT_CLR;
0084
0085 LOONGSON_PCIMAP_CFG = (addr >> 16) | type;
0086
0087
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
0098 if (LOONGSON_PCICMD & (LOONGSON_PCICMD_MABORT_CLR |
0099 LOONGSON_PCICMD_MTABORT_CLR)) {
0100
0101
0102
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
0116
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