linux/arch/mips/pci/ops-loongson3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/types.h>
   3#include <linux/pci.h>
   4#include <linux/kernel.h>
   5
   6#include <asm/mips-boards/bonito64.h>
   7
   8#include <loongson.h>
   9
  10#define PCI_ACCESS_READ  0
  11#define PCI_ACCESS_WRITE 1
  12
  13#define HT1LO_PCICFG_BASE      0x1a000000
  14#define HT1LO_PCICFG_BASE_TP1  0x1b000000
  15
  16static int loongson3_pci_config_access(unsigned char access_type,
  17                struct pci_bus *bus, unsigned int devfn,
  18                int where, u32 *data)
  19{
  20        unsigned char busnum = bus->number;
  21        int function = PCI_FUNC(devfn);
  22        int device = PCI_SLOT(devfn);
  23        int reg = where & ~3;
  24        void *addrp;
  25        u64 addr;
  26
  27        if (where < PCI_CFG_SPACE_SIZE) { /* standard config */
  28                addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
  29                if (busnum == 0) {
  30                        if (device > 31)
  31                                return PCIBIOS_DEVICE_NOT_FOUND;
  32                        addrp = (void *)TO_UNCAC(HT1LO_PCICFG_BASE | addr);
  33                } else {
  34                        addrp = (void *)TO_UNCAC(HT1LO_PCICFG_BASE_TP1 | addr);
  35                }
  36        } else if (where < PCI_CFG_SPACE_EXP_SIZE) {  /* extended config */
  37                struct pci_dev *rootdev;
  38
  39                rootdev = pci_get_domain_bus_and_slot(0, 0, 0);
  40                if (!rootdev)
  41                        return PCIBIOS_DEVICE_NOT_FOUND;
  42
  43                addr = pci_resource_start(rootdev, 3);
  44                if (!addr)
  45                        return PCIBIOS_DEVICE_NOT_FOUND;
  46
  47                addr |= busnum << 20 | device << 15 | function << 12 | reg;
  48                addrp = (void *)TO_UNCAC(addr);
  49        } else {
  50                return PCIBIOS_DEVICE_NOT_FOUND;
  51        }
  52
  53        if (access_type == PCI_ACCESS_WRITE)
  54                writel(*data, addrp);
  55        else {
  56                *data = readl(addrp);
  57                if (*data == 0xffffffff) {
  58                        *data = -1;
  59                        return PCIBIOS_DEVICE_NOT_FOUND;
  60                }
  61        }
  62        return PCIBIOS_SUCCESSFUL;
  63}
  64
  65static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn,
  66                                 int where, int size, u32 *val)
  67{
  68        u32 data = 0;
  69        int ret = loongson3_pci_config_access(PCI_ACCESS_READ,
  70                        bus, devfn, where, &data);
  71
  72        if (ret != PCIBIOS_SUCCESSFUL)
  73                return ret;
  74
  75        if (size == 1)
  76                *val = (data >> ((where & 3) << 3)) & 0xff;
  77        else if (size == 2)
  78                *val = (data >> ((where & 3) << 3)) & 0xffff;
  79        else
  80                *val = data;
  81
  82        return PCIBIOS_SUCCESSFUL;
  83}
  84
  85static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn,
  86                                  int where, int size, u32 val)
  87{
  88        u32 data = 0;
  89        int ret;
  90
  91        if (size == 4)
  92                data = val;
  93        else {
  94                ret = loongson3_pci_config_access(PCI_ACCESS_READ,
  95                                bus, devfn, where, &data);
  96                if (ret != PCIBIOS_SUCCESSFUL)
  97                        return ret;
  98
  99                if (size == 1)
 100                        data = (data & ~(0xff << ((where & 3) << 3))) |
 101                            (val << ((where & 3) << 3));
 102                else if (size == 2)
 103                        data = (data & ~(0xffff << ((where & 3) << 3))) |
 104                            (val << ((where & 3) << 3));
 105        }
 106
 107        ret = loongson3_pci_config_access(PCI_ACCESS_WRITE,
 108                        bus, devfn, where, &data);
 109
 110        return ret;
 111}
 112
 113struct pci_ops loongson_pci_ops = {
 114        .read = loongson3_pci_pcibios_read,
 115        .write = loongson3_pci_pcibios_write
 116};
 117