Merge branch 'pm-cpufreq'
[linux-2.6-microblaze.git] / arch / mips / pci / ops-vr41xx.c
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
22 static 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
48 static 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
76 static 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
110 struct pci_ops vr41xx_pci_ops = {
111         .read   = pci_config_read,
112         .write  = pci_config_write,
113 };