linux/arch/mips/pci/ops-vr41xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  ops-vr41xx.c, PCI configuration routines for the PCIU of NEC VR4100 series.
   4 *
   5 *  Copyright (C) 2001-2003 MontaVista Software Inc.
   6 *    Author: Yoichi Yuasa <source@mvista.com>
   7 *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.org>
   8 */
   9/*
  10 * Changes:
  11 *  MontaVista Software Inc. <source@mvista.com>
  12 *  - New creation, NEC VR4122 and VR4131 are supported.
  13 */
  14#include <linux/pci.h>
  15#include <linux/types.h>
  16
  17#include <asm/io.h>
  18
  19#define PCICONFDREG     (void __iomem *)KSEG1ADDR(0x0f000c14)
  20#define PCICONFAREG     (void __iomem *)KSEG1ADDR(0x0f000c18)
  21
  22static inline int set_pci_configuration_address(unsigned char number,
  23                                                unsigned int devfn, int where)
  24{
  25        if (number == 0) {
  26                /*
  27                 * Type 0 configuration
  28                 */
  29                if (PCI_SLOT(devfn) < 11 || where > 0xff)
  30                        return -EINVAL;
  31
  32                writel((1U << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) |
  33                       (where & 0xfc), PCICONFAREG);
  34        } else {
  35                /*
  36                 * Type 1 configuration
  37                 */
  38                if (where > 0xff)
  39                        return -EINVAL;
  40
  41                writel(((uint32_t)number << 16) | ((devfn & 0xff) << 8) |
  42                       (where & 0xfc) | 1U, PCICONFAREG);
  43        }
  44
  45        return 0;
  46}
  47
  48static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where,
  49                           int size, uint32_t *val)
  50{
  51        uint32_t data;
  52
  53        *val = 0xffffffffU;
  54        if (set_pci_configuration_address(bus->number, devfn, where) < 0)
  55                return PCIBIOS_DEVICE_NOT_FOUND;
  56
  57        data = readl(PCICONFDREG);
  58
  59        switch (size) {
  60        case 1:
  61                *val = (data >> ((where & 3) << 3)) & 0xffU;
  62                break;
  63        case 2:
  64                *val = (data >> ((where & 2) << 3)) & 0xffffU;
  65                break;
  66        case 4:
  67                *val = data;
  68                break;
  69        default:
  70                return PCIBIOS_FUNC_NOT_SUPPORTED;
  71        }
  72
  73        return PCIBIOS_SUCCESSFUL;
  74}
  75
  76static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where,
  77                            int size, uint32_t val)
  78{
  79        uint32_t data;
  80        int shift;
  81
  82        if (set_pci_configuration_address(bus->number, devfn, where) < 0)
  83                return PCIBIOS_DEVICE_NOT_FOUND;
  84
  85        data = readl(PCICONFDREG);
  86
  87        switch (size) {
  88        case 1:
  89                shift = (where & 3) << 3;
  90                data &= ~(0xffU << shift);
  91                data |= ((val & 0xffU) << shift);
  92                break;
  93        case 2:
  94                shift = (where & 2) << 3;
  95                data &= ~(0xffffU << shift);
  96                data |= ((val & 0xffffU) << shift);
  97                break;
  98        case 4:
  99                data = val;
 100                break;
 101        default:
 102                return PCIBIOS_FUNC_NOT_SUPPORTED;
 103        }
 104
 105        writel(data, PCICONFDREG);
 106
 107        return PCIBIOS_SUCCESSFUL;
 108}
 109
 110struct pci_ops vr41xx_pci_ops = {
 111        .read   = pci_config_read,
 112        .write  = pci_config_write,
 113};
 114